In the Turkish locale, "INFO".lower() != "info"
github.com
github.com
It seems to me that in practice, it's extremely rare to want to change case of real, natural-language text. When I have natural-language text, it's just a blob to me, and I don't want to touch it.
The only time I ever want to lower-case or capitalize something, I'm working with identifiers meant for computer -- not human -- consumption. Usually, specifically, I'm dealing with identifiers that have annoyingly been defined to be case-insensitive even though the only humans that ever see them are programmers and programmers hate case-insensitivity. HTTP headers are a common example.
I mostly write C++, and I end up writing code like:
for (char& c: str) {
if ('A' <= c && c <= 'Z') c = c - 'A' + 'a';
}
Later on, some well-meaning developer on my team will come along and say "Ugh what is this NIH syndrome?" and then they "clean it up" as: #include <ctype.h>
for (char& c: str) {
c = tolower(c);
}
And then I have to say NOOOOOOO DON'T DO THAT YOU HAVE NO IDEA WHAT tolower() REALLY DOES!I struggle to imagine any real use case where you'd actually want locale-dependent tolower() other than, maybe, a word processor -- but if you're writing a word processor, you're probably not going to be depending on the language's built-in string APIs to do your text manipulation.
Maybe I should have my own tolower() function that I can call so I only have to write the comment once but it just feels ridiculous somehow.
I mean, it's clearly the right thing to do here but I can predict the conversation that will inevitably result... "You wrote your own tolower() function? Why?" "The standard one is horribly broken." "How could a function that lower-cases a letter be broken??? Jesus Kenton your NIH syndrome is out of control." "Sigh..."
(Slightly more seriously, any particular time I need to lower-case something, it takes 10 seconds to write out the code, but would take 10 minutes to find a good place to define a reusable function and exactly what its API should be, and so it never seems worth the effort in the moment. Just like how most messy code comes to be.)
But I too feel the cognitive (and social!) burden of introducing a new function. It's not just "where do I put this", but "how do I convince the team I know what I'm doing since 15 years of experience clearly isn't enough and developers (mostly rightly) ignore positional authority and seniority".
I have noticed some coworkers have their ego gratified by being right while everyone else is wrong. Instead of simply explaining what they are doing when they are doing it, they will do something that looks wrong in a very noticeable way and wait for the backlash. The backlash gives them an opportunity to show everyone else how they were right while everyone else was wrong and also an opportunity to play victim. However, in SW development - it is not just the technical details - your behavior also matters in a big way.
In this particular case, the correct approach is to create your own library function with appropriate comments. This is why the concept of a library function was invented. It is its entire raison-d'etre. However, you are doing everything but that. Including providing justifications in hacker news comments instead of your source code.
Now inevitably, someone will change your inline code to use to_lower. This will give you an opportunity to scream bloody murder, show how other engineers don't really understand technical details, correct them and also play victim. Create a library utility with comments and link it in - End of story.
But seriously, I'm not here to lecture you, but personally I'd appreciate having a teammate educate me on the undesired behavior and have a nice function I could use to ensure my own code doesn't break user input
Many of these are obvious to many people here, but some aren't.
Even I can admit that some of the stuff in this thread is not obvious at all.
#include <kentonv.h>https://github.com/capnproto/capnproto/tree/master/c++/src/k...
You know you wrote it 49 times before, but the person reading the code probably doesn't. It only changes your experience not everyone else's.
If it's the same codebase, just write that function :)
And if that test also happens to validate that the documentation is accurate, that is a nice side benefit.
You might be being serious, so I'll indulge. How would a test that will never break, for a function that would never be changed (because look at it), that lives in a different part of the directory structure, be worth even one second extra time or thought to write it, over-and-above the descriptive comment that is longer than the code itself, and lives discoverably right next to the code itself?
At that point, just leave the test and check it in.
Often, though, you can verify that your code works using a REPL.
I'm also a huge fan of how doc-tests in some languages that make the tests are part of the documentation, and neatly 'cohere' them to the function itself. At which point I'm happy to leave them in, as the tests-as-documentation are harder to miss, and are actually instructive.
Machine-time to run tests is cheap (if it's not in your codebase, then I agree that your benefit calculus may be different) - human cognition and awareness to prevent mistakes is valuable.
> a test that will never break, for a function that would never be changed
I'll refer you to the OPs low-tech to-lower function, which is reductively simple, and never should be altered, with a comment as to why.
> Comments can be ignored, moved, misinterpreted.
Don't disagree with this. Someone lacking competence and care may ignore a comment, is incapable of comprehension, or just moves things for no reason. This should be caught at review.
Tests aren't infallible either. They can be invalidated, disabled because someone lacking competence decided it was the easiest way to move forward. This should be caught at review.
Edit: I'll address some of your other points more specifically...
> The only way to make the build fail if someone has (incorrectly) replaced the "complex toLower" with the (incorrect) "built-in toLower" is to delete or change the corresponding test
In OP's precise example, a worse thing can happen. They can shrug their shoulders and just use the built-in directly. Human-context business-value explication has more powerful benefit here.
> which rings way more alarm bells than a vague recollection of "hey, didn't there used to be a comment around here that said we shouldn't change this?"
If no-one's reviewing when someone changes the actual code and it's adjacent comments, who's reviewing the changes to the tests?
> human cognition and awareness to prevent mistakes is valuable.
Extra code comes at a maintenance and cognition cost. Maybe one trivial test seems like a minor cost, but how about the maintenance of 1000s of tests that (ought to) always pass?
The cost of writing a single test case is not more than the cost of diagnosing what change broke your code for Turkish users.
Now there's always a point where maybe the infrastructure for testing that kind of thing doesn't exist, so writing your one "simple" test case takes a bunch of time, but on the plus side, future similar "simple" test cases will be easy at that point. And no one has to track down why your code is broken in turkey.
Many years ago while I worked on IM/IMEs on Mac and windows I spent maybe a week working on code that allowed an IME to be implemented in JS (within the webkit test harness), so it was possible to test, and prevent regressions that kept on being reintroduced by people changing layout and/or editing code in ways that are "obviously correct" for US/English keyboards. The win from that week is many regressions that were caught before they were even committed, and the ability to completely rewrite the text input system to support IMEs on non-mac platforms.
The big difference is it looks deliberate, instead of just code written by someone trying to micro-optimize, be very clever, or who just didn't realize tolower() exists. Most people will pause before just replacing it, and likewise it should trigger questions in the PR.
Locale name is iv-IV.
https://en.m.wikipedia.org/wiki/Email_address#Internationali...
On many documents, including Turkish passport and identity card and many (all?) other passports, names are written in all caps. Maybe toLower() is not that useful, but toUpper() is crucial in any application where you are dealing with real person names.
Plus, there's the issue of diacritical marks. Irish keeps long marks over capitals, but French drops accents. Do you plan to do é => É (required for Irish - POBLACHT NA hÉIREANN is the all-caps version of Poblacht na hÉireann [the Republic of Ireland]) or é => E (common practice for French)? You have to get it right, and you have to know the language to do that. (Poblacht na hÉireann also illustrates the fact that initial caps is also a language-dependent idea; you absolutely can't write Poblacht Na Héireann - that makes my eyes burn just looking at it.)
(And before you say, well, Irish isn't a language spoken by very many people, remember that it's an official language of the European Union. If you're writing software to be used by EU agencies, you're going to have to care.)
Official position of both Académie française and Office québécois de la langue française is that accents must be preserved in capital letters. However, it is common in France to drop them, while they are almost always preserved in Québéc. I have heard that the reason is that European French keyboard layout makes it difficult to type accented capital letters, unlike Québécois French layout which makes writing them easy. But I am not sure if this is the cause rather than the effect of the practice.
I have an anecdote on this: on birth certificates, family names are written in capital letters. It turns out my partner name ends with a É which was written as E in her birth certificate. She never noticed (it had never prevented her to get national ID with her name properly accented) until we had our first kid which has both our names, and they refused to have the name accented until we had my partner's birth certificate updated (which as you can imagine is quite an adventure, since you need to dig ancient family birth certificates to prove it was originally written with an accent...).
http://j.poitou.free.fr/pro/img/tkn/tw-image.jpg
This idiocy carried over. The recent layout update makes dead accents more accessible:
But I haven't seen much adoption yet.
Even more if you consider that the minus sign there is not the character - that is used by every programming language.
And there are two more on the 8 key.
I like the mac international keyboard layout, but it still only provides for 4 of those: the non-breaking hyphen and the "proper" minus sign are lacking.
I like that the "new azerty" provides for pretty much every diacritic, even those which are not in use in french.
korean is worse. they base off of 10k, not 1000. so a million is hundred ten_thousand. bagman. but as bad as that is, it's no 97 amirite.
What's weird is I sometimes, even 10 years ago, would get an email from people in France, and it would have an accented A. Like, how did they do that..
toLower and toUpper should only be used for presentation, but all case-insensitive operations need to be done with casefold.
It's only tolower() and toupper() specifically that are broken because they expect to be able to do their job on a single byte, which is no longer possible with UTF-8.
Meanwhile, using tolower() to lower-case an HTTP header name won't give you the correct results if the locale is set to Turkish with the ISO 8859-9 character set, which is 8-bit, and where tolower('I') will produce the byte 0xFD which is 'ı' in this character set.
Is there something similar for C and C++? It could help in your case, by making your well-meaning colleagues aware of the issue.
At least Android developers are advised to use Locale.US: https://developer.android.com/reference/java/util/Locale
> The default locale is not appropriate for machine-readable output. The best choice there is usually Locale.US – this locale is guaranteed to be available on all devices, and the fact that it has no surprising special cases and is frequently used
It would be indeed interesting to see in which features these two locales actually differ.
[1] https://www.icao.int/publications/pages/publication.aspx?doc...
Also got my address screwed up on account of living at a half address.. 1/2 some street #42
Yes. In a system I'm about done with, there is a sortable chart of dates and times. In some languages day and month names are capitalized, and in some they are not.
There are similarly tons of cases where you reduce everything to lowercase without accents for searching and indexing purposes. Depending on your setup, your database might handle that for you, but there are edge cases where you need to do it at the application level.
Long story short, every string has a locale, and you should never change the case of something without specifying its locale. Either be explicit that it's American English or ASCII or Latin1 or whatever... or that it's something else. Never leave someone reading the code guessing.
I am skeptical if someone thinks they need to do this and how they will get it done.
Eg. Looping through and capitalizing the first gylph after breaking whitespace regardless of locale is not the way to go, but I guarantee you a nontrivial amount of people reading this would write exactly that if asked to solve the high level problem.
I find it annoying when software or even in some cases human typists try to enforce English language title case. Some other languages have different rules for titles and capitalization and seeing the English rules enforced out of context can be jarring.
I use the citation manager Zotero a lot. It's necessary to store all the titles of journal articles and books in sentence case (e.g. "Issues regarding the economy of France") because some publications require citations to use sentence style (remains unchanged) while others require title style ("Issues Regarding the Economy of France").
And obviously the solution cannot be naive, but is language-dependent, so that in English words like "the" or "in" don't get capitalized. And as the rules for titles are obviously language-dependent, so it goes without saying that the algorithm would have to be localized.
(Note that while it's relatively trivial to convert from sentence case to title case in English, it's impossible to automate in the opposite direction, because you never know if a capitalized term in the title is a proper noun or not.)
Strictly speaking you can't do that either:
"Latine et videtur".totitle = "Latine et Videtur"
"I et some food".totitle = "I Et Some Food"
I suspect that fails less often though.So yes, it's extremely common. It's done on tons of websites, for tons of mail addresses (ever receive an all-uppercase address on a delivery? same issue.), and tons and tons and tons of emails and legal documents (woe to those with last names like McCormick).
I most often use title case mappings in the context of replacements of names into diagnostic messages. I.e. you have n types of objects and m messages like “${foo} not found” or “More than one ${foo} required”, and perform title case mapping on ${foo} depending on whether it is at the start of the message (sentence) or not.
It's not an uncommon requirement, though probably not often in a locale sensitive way, so you can often get away with just doing the right thing for one locale.
To do it generally, you probably need to research appropriate handling per locale (likely, what your client wants done in the particular locale, since I'm not sure there is usually just one way; I know there are multiple variations in en-US), and then have a master function that takes the text and target locale and applies the correct locale-specific title casing rules.
If you are collecting data which include people's names or addresses you probably want localization to be applied correctly so that you can compare data coming from different sources and possibly with different cases. Having your name spelled differently in different documents can cause a non trivial amount of problems with an overzealous bureaucracy.
How do you lowercase without localization? Remember all text isn't English. Unless you're actually asking if anyone has ever had a use case for lower-casing non-English text?
Maybe for automatically changing the case of user input (auto-correcting capitalization, etc.).
It's horrifically wrong, of course, but no one is going to think you're a reasonable person for insisting that correct wins over nice.
Imagine a real-world scenario where you're displaying a list of names of users, where the users got to type in their own names. You can either use what users typed in, or you can do something like process it so it's in the American idea of initial caps. You can't possibly do localization, since it's a list of names of people in the US, so it's melting pot of names from all over the world, and you never asked for user input of what you'd use to localize it anyway [and no, you absolutely can't figure that out from just the name itself]. You can't use what users typed in, because the design team thinks that looks like a horrible mess (and it is; users are laughably bad at data entry). So the design team wins, and you butcher everything by pretending that toLower() plus toUpper() for the first character of every word is a sensible thing to do. (And yes, that's a painful real-world example of software I've shipped and that was used by millions of people.)
Well, it's always been exclusively in American English, but I've certainly used it in cases where I was doing text transforms for display, so, yeah, though it's not the most common case.
https://doc.rust-lang.org/std/string/struct.String.html#meth...
But if you consider the other writing systems, having case conversion feature in locale library actually harm the localization effort. It's not easy to make it no-op. The implementation of locale library are generally poor quality because the implementer has no idea how other languages works.
Another example is singular/plural support. It just burden the localization effort because for languages which no such concept, the localization work must ensure that presence of such library doesn't harm their language.
Some people is under the delusion that locale library must have more features to support his native languages not so important traits. While what really necessary is just forget about supporting minor language traits that are not universal among the languages.
The text should be considered binary blob and most program should pass it left to right without modification.
Human text is much much more complex than any computing protocol you're ever going to engage with.
The question is "which one should be default", and that's a more complicated question.
- i <-> İ
- ı <-> I
We love our dots and preserve them. For a more detailed read, please see:
If your program can pass “The Turkish Test”, you pass a lot of others too.
That connection through language goes a long way.
müqəddəs bacı millət :)
> The use of "i" resulted in an SMS with a completely twisted meaning: instead of writing the word "sıkısınca" it looked like he wrote "sikisince." Ramazan wanted to write "You change the topic every time you run out of arguments" (sounds familiar enough) but what Emine read was, "You change the topic every time they are fucking you" (sounds familiar too.)
Also the article explicitly says "it looked like he wrote". So when you see red, that last letter can become anything and nothing would change.
> - ı <-> I
After seeing this, I don't understand how the rest of us can fail to have the same distinction. There's something logically beautiful -- like the rhyme in a good poem -- about artificial languages (or, in this case, alphabets) that naturally evolved languages just cannot compete with.
Speakers of Turkish generally build words with vowels from either of these exclusive groups:
aıuo
eiüö
You see? They could write "ä" instead of "e" to have all bright vowels dotted and mirror the symmetry. But because "e" was already available and pronounced like that in other dominant languages of the time, they stuck to it. No need to break conventions. This didn't work for "ı" because there was no corresponding letter in the Latin alphabet. So they loped off the dot from i and called it a day. A pragmatic decision. Except that the capital version had then to be dotted to keep the distinction. That caused a lot of headaches downstream.
https://en.wikipedia.org/wiki/Vowel_harmony
...but it's notably absent from the Indo-European languages.
Turkish preserves the dots of i, ö and ü in their capital versions, but not with j. The capital J is dotless.
The first letter of russian alphabet is А, the last one is Я. So it's natural to try to match russian words with '[А-Яа-я]+'. But this is a recipe for disaster, this regexp doesn't match words with 'Ё' in them like "Артём".
This is due to the fact that regexp ranges work on byte values. All letters of russian language have neatly ordered byte values, except for the Ё.
Ss
SS
So my phone doesn't have that yet!
$ echo Test | grep -oP '[[:alpha:]]+'
Test
$ echo Артём | grep -oP '[[:alpha:]]+'
$ echo Артём | grep -oP '[А-Яа-я]+'
Арт
м
This thing works, though I've never seen one in the wild: $ echo Артём | grep -oP '[\p{Cyrillic}]+'
Артёмhttps://regular-expressions.mobi/unicode.html
$ echo Артём | grep -oE '[[:alpha:]]+'
АртёмIt is practically always wrong to match on [a-z] unless you’re parsing a computer language whose spec guarantees that it works.
Do you have to press some obscure keyboard shortcut?
In macOS, you can either use Command-u (for "umlat") followed by i, or hold down the i key for a second and press 2 to select the ï from the pop-up menu.
option-u (aka alt-u).
Generally speaking, command is for application-level or os-level commands, control is for text edition, and alt is for alternate characters (all can be shifted and command "overrides" the rest).
This has happened with every single Apple keyboard I've ever used. I suspect it's my fault, since I'm a key pounder, having learned to type on an IBM Selectric typewriter.
It's not very clear why the Swedish keyboard has that key, since ä and ö each have their own keys. The layout has other quirks as well, such as keys for §, ½ and the useless "currency sign", ¤.
BTW, the dead key could be from german, for writing their U:s.
It wouldn't have been much of a bother, had I not used the key as my Emacs leader...
I found "Polish international" [1] layout which honestly can be perfect for many people. It's optimized to be compatible with regular Polish keyboard (hence with US keyboard too), and maybe not the fastest if you type a lot special chars, but it's extremely intuitive:
ï = AltGr+:, i
ü = AltGr+:, u
é = AltGr+/, e
è = AltGr+\, e (since it's extremely common, also aliased as AltGr+w)
If you're Windows based and want US-compatible keyboard layout that allows easily typing any special chars, I highly recommend it.
[1] https://translate.google.com/translate?sl=pl&tl=en&u=https%3...
The Alt-13x codes are not as quick as the Azerty keys, but good enough and once memorized are fairly easy with a keyboard that has a keypad (most PCs do, even my laptop). This is especially true because they are done with both hands simultaneously, as opposed to something like Cmd-e+e on a Mac. Actually, they are faster than finding the accented characters on my QWERTY virtual keyboard as I type this comment on iOS.
Those AltGr- combos seem complicated to me, I would much prefer a system such as AltGr-e =é, then AltGr-ee=è, AltGr-eee=ê, etc. To me that would be more intuitive than remembering the composing character (slash for aigüe, etc).
The New Yorker writing things like coöperate and reëlect is probably the most infamous, although they are not the only ones.
The Guardian style guide says to use spellings exposé, lamé, résumé, and roué – but not café. Although, when giving the name of an organisation/institution (restaurants and cafés included), the article should use whatever spelling is preferred by the management, including their choice about how to spell cafe/café (when that word is part of their name).
Personally, I'd always write café in formal English, because cafe just looks wrong to me. However, in something informal like a text message I probably wouldn't bother.
FWIW, Economist explicitly names Naive as one to use without diacritic: https://cdn.static-economist.com/sites/default/files/store/S...
It's always something easy to remember, like " for umlauts, o for circles (©, ®), obviously ' for accents (ń) and so on.
Also, Qt5 broke support for multi-character results when using compose sequences (everything after the first character is ignored).
On Linux there is also a "US alternate international" layout with some extra dead keys to make it easier to do things like š or ž (Ctrl-RightAlt-< followed by s or z, respectively).
That's the whole point of the diaeresis.
Here are some examples to match your string all of them use PCRE flavor
(UCP)[[:alpha:]]+
(UCP)[[:alnum:]]+ This would includes digits
(UCP)[[:word:]]+ This includes "word" chars
(UCP)\w+ same as above
'ß'.toUpperCase(); // returns 'SS'
https://en.wikipedia.org/wiki/Capital_%E1%BA%9E
(with German language authorities recently endorsing the idea that ß can have a distinctive uppercase form "ẞ")
Normally there is no such thing as a capital ß, so it was decided that if for some unreasonable reason you do uppercase it you go with SS.
But then for some all-caps usages this is not right. E.g. a all caps name of an restaurant as placed above the restaurants door. In which case it was common to have a ß in a all-caps name like FOOßBAR. So they decided that for reasons like this we now have an (EDIT: semi?) official uppercase ß.
So all in all this and other examples in other languages mean you should never do a case insensitive comparison by upper/lower casing both sides, it won't work reliable.
Behaviour like this is definitely a good reason why: sorting, changing case, etc should be consistent when dealing with strings used as constants and identifiers, but Python's .lower() behaviour makes sense in a localizable string context.
https://docs.microsoft.com/en-us/dotnet/api/system.globaliza...
Support at the type level would be a lot less verbose, but support at the function level is already much better than many other popular languages.
It would take slightly more memory but not significant on modern machines.
You could treat it as a series of string slices with different locales `[("info", "en"), (": ", ""), ("bağlantı kesildi", "tr")]`. That would work correctly, and you could now uppercase each slice according to its appropriate locale, but it wouldn't really be low overhead anymore. Maybe still worth it. It would be an interesting approach that might even be able to be implemented pretty seamlessly as a library in some languages (C++ or rust for example)
Example: logging.log("INFO", i"This is a localizable string")
In the i18n world, we could gather i-strings just like gettext does (where it looks like `logging.log("INFO", _("This is a localizable string")`). The language could then have other useful hooks/behaviours into that datatype, and definitely one of them would be whether various methods have i18n behaviour enabled on them, versus using a C locale.
The problem was never gazillions of code pages, but our inability to write C to deal with that amount of complexity circa 1990.
With modern machines, and good programming languages with good type systems, I absolutely think we could store a language per string, and concatenate into a polylinguistic rope if needed.
This would hopefully push us away from stringly-typed crap in general.
I wish you would give an example instead of just proclaiming crapness. You know, so we n00bs can learn something.
;)
Sorting of strings is language dependent, but I don't know that there's a defined order for mixed language lists, so I guess user's context works if you're sorting for user purposes, but if you're sorting for machine purposes, you better not use the locale aware sort without telling it a hardcoded locale that doesn't change between localization library versions.
The flaw in Unicode is that it punts on the intrinsic complexity---pretending that codepoints have language-independent, plain-text, semantic meaning.
A couple of threads that have molded my views over time:
I can't write my name in Unicode https://news.ycombinator.com/item?id=9219162 (Specifically these two comments https://news.ycombinator.com/item?id=9220530 and https://news.ycombinator.com/item?id=9220970)
Why isn't the external link symbol in Unicode? https://news.ycombinator.com/item?id=23016832
> Pretending "plain text" isn't an oxymoron
FTFY :)
E.g. lookalike charaters, and social engineering by using a vs а. (One is Cyrillic). I don't want to even define "a == а". I want Latin and Cyrillic to be different types of characters, and that expression to be ill-typed.
This solves the Turkish problem, where the upper case I is two different charters in two different types (Turkish Roman script?), and the case folding functions likewise have disjoint types.
How do you concatenate English and Ру́сская text, and what is the type of this sentence?
If you want to build a polylinguistic rope you can certainly do that with Unicode, but you won’t have solved anything because language alone without context doesn’t really define many of the operations you’re describing.
The answer is usually the same as “doctor it hurts when I...” — stop doing it. Stop manipulating user input without context. Stop trying to limit user visible strings by character count, use pixel width in the rendered font. And so on.
Sure it does; the Unicode Character Database includes fields for the lowercase, uppercase and titlecase mappings. But it also acknowledges that these are just default mappings, and may need to be tailored for specific languages/locales.
If all that good effort went into something along the lines I am describing, where languages, or at least scripts, cannot be arbitrary mixed at the character level, I think we would have an even better result with the same level of effort.
That said, any "multicode" better describe the interopt with "unicode" in great detail for practical reasons. Still this is the "FFI", and one can be careful to let it not muddle things by e.g. not allowing every unicode string to be imported without additional metadata.
I am happy to define how to translate Multicode to Unicode, but I wouldn't want any of the internal notions of Multicode to be defined in terms of that translation.
https://tools.ietf.org/html/rfc2482
But it was deprecated later on:
(Somewhat ironically, the previous thread on that mailing list is about the struggles of case folding in a general fashion across multiple language scripts[2])
Edit: I also found [3], which offers the following:
----
- Most of the data sources used to assemble the documents on the Web will not contain these characters; producers, in the process of assembling or serializing the data, will need to introspect and insert the characters as needed—changing the data from the original source. Consumers must then deserialize and introspect the information using an identical agreement. The consumer has no way of knowing if the characters found in the data were inserted by the producer (and should be removed) or if the characters were part of the source data. Overzealous producers might introduce additional and unnecessary characters, for example adding an additional layer of bidi control codes to a string that would not otherwise require it. Equally, an overzealous consumer might remove characters that are needed by or intended for downstream processes.
- Another challenge is that many applications that use these data formats have limitations on content, such as length limits or character set restrictions. Inserting additional characters into the data may violate these externally applied requirements, and interfere with processing. In the worst case, portions (or all of) the data value itself might be rejected, corrupted, or lost as a result.
- Inserting additional characters changes the identity of the string. This may have important consequences in certain contexts.
- Inserting and removing characters from the string is not a common operation for most data serialization libraries. Any processing that adds language or direction controls would need to introspect the string to see if these are already present or might need to do other processing to insert or modify the contents of the string as part of serializing the data.
----
Other than #3 (the one about string identity), I find these wholly unpersuasive. And even #3 isn't even that great a reason considering that programmatic processors have to deal with that issue anyway due to case folding.
[1] https://www.unicode.org/mail-arch/unicode-ml/y2010-m11/0039....
[2] https://www.unicode.org/mail-arch/unicode-ml/y2010-m11/0038....
import locale
sorted(list_of_strings, key=locale.strxfrm)
To sort using the current loacale, which many people forget.In the Turkish locale, the Unicode LATIN CAPITAL LETTER I becomes a LATIN SMALL LETTER DOTLESS I. That’s not a lowercase “i”.
“US centric” is one way to say it
I think you mean April.
Maybe if dang sees this, it could be reparented?
I don’t know why so many languages have string functions that should take a locale but provide an overload that doesn’t and which uses the system locale as the default. It can’t be what many developers actually want, yet it has become the norm. Worse, code using a default locale appears to work on the developers machine and in production, until someone parses a number in France or lowercases a string in Turkey, which is a late and expensive discovery of the bug.
The default shouldn’t be the system locale, it should be an invariant locale. And I’ll go so far as arguing this invariant locale should be invariant across systems (meaning it can’t just defer to a system C library either).
That was a learning experience.
Perhaps it’ll make you feel better about your parsing bug that even the C# compiler (Roslyn) code base had several of these issues.
That‘s a relict from the past, before Unicode became prevalent, where systems used to ever only work in a single locale, and where users expected applications (running locally of course) to use the local system locale. Hence applying the system locale to everything was the standard behavior for applications. The C standard library was defined in that way, and since then every other runtime (usually based on C at some level) does the same.
If you call a case-related method like `lower` on a Python string, the behavior you get is based on tables which are built into Python, taken straight from the Unicode standard's data files, and completely independent of your system configuration.
It would nice to also have the option of explicitly using a particular locale. Here's a discussion from 2019 about potentially adding that option: https://bugs.python.org/issue37848 You'll be glad to see everyone there agrees the default should remain invariant.
Relevant bug report here: https://bugs.openjdk.java.net/browse/JDK-8047340
If you just casefold two strings and compare them, it's still a bug. You need to normalize them to NFKC first.
https://en.m.wikipedia.org/wiki/Dotted_and_dotless_I
Did not know Istanbul is actually İstanbul.
You can just make string lowercase() uppercase() function work the same everywhere, regardless of locale settings. Provide a special case function lowercaseTR() or so. This works very well in Go.
By the way, Azerbaijan has the same problem because they accepted help from wrong guys when they switched to Latin.
Huh, that works well if we know the input string is in Turkish. What if this information is not available as you're writing the code?
And what will lowercase()/uppercase() be hard coded to do, and what are they supposed to output when the input isn't ASCII?
The workaround in the OP was added in 2006 (note the reference to an issue on "SF", i.e. SourceForge -- another era!), and is now long obsolete.
"Those not comfortable with toxic language should pretend this is a religious text."
https://github.com/mpv-player/mpv/commit/1e70e82baa9193f6f02...
Python 3.7.3 (default, Jul 25 2020, 13:03:44)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from locale import *
>>> setlocale(LC_ALL, 'tr_TR.UTF-8')
'tr_TR.UTF-8'
>>> 'INFO'.lower()
'info'[Clang 11.0.0 (clang-1100.0.33.12)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from locale import *
>>> setlocale(LC_ALL, 'tr_TR.UTF-8')
'tr_TR.UTF-8'
>>> 'INFO'.lower()
'info' >>> '🧘 ️'.lower()
'🧘\u200d️'
>>> exit()
There's something wrong with emojis + lower() though
Author: Guido van Rossum <guido@python.org>
Date: Tue Oct 9 03:46:30 2007 +0000
Replace all (locale-dependent) uses of isupper(), tolower(), etc., by
locally-defined macros that assume ASCII and only consider ASCII letters.For example, MS SqlPackage, used for deploying schema, is case-insensitive... But that also means changes to text constants within your stored procs do not get treated as changes.
This is old but still valid reading...
For example, instead of .lower(), we can have .lower_ascii(), .lower_turkish() or .lower(locale) . But I know it would be tedious to use if you need to specify it everytime, so it makes sense to have a .lower(locale=DEFAULT_LOWER_LOCALE) . As for what should DEFAULT_LOWER_LOCALE be, it is worth debating, but I think it shouldn't introduce unexpected behavior.
Why on earth would you hard-code these, instead of simply call a lowercase function in the en-US locale?
These are English words. Naively lowercasing them according to whatever locale the server or user has set seems like a terrible programming practice. Any call to a lowercase function should be explicitly including an argument that specifies it's English, no?
In the same way we've all learned to never store times without an explicit timezone (even if it's UTC), or locate a string offset without knowing your encoding... you should never perform language transformations (case changes, accent removal, etc.) without a locale.
Hardcoding these things is just patching over the symptoms without addressing the cause, no?
Unicode calls it HYPHEN-MINUS. It does also have an unambiguous ‘−’ MINUS SIGN as well as ‘‐’ U+2010 HYPHEN and the various dashes, but most people use bad keyboard layouts.
And different "SS" for any case where the lowercase was an sz, of course at some point Germany introduced an uppercase SZ character to avoid that round trip loss issue, but we still have tons of text that use the old sz -> SS conversion. Also note that "y" in Germany, not all German speaking countries follow the same rules for sz, some dropped it entirely. We basically need something like the time zone database to have even a snowballs chance in hell to handle text correctly.
https://web.archive.org/web/20151007005513/http://www.911cd....
> KeyError: 'Info'
https://github.com/angular/angular.js/commit/1daa4f2231a89ee...
I believe this has proven to be a mistake but I'm not an expert. I don't know why it wasn't done.
There is a good Unicode FAQ on the topic: < http://unicode.org/faq/casemap_charprop.html >
E: to elaborate, I'm not sure whether the independence of case handling and normalization is guaranteed anywhere, and if we for example were to change the uppercase of ſ to something else than S then its compatibility forms' (s) case handling would differ. In practice the SpecialCasing.txt is designed to "make it work" (e.g. ſ uppercases to S).