Který systém píše diakritiku až po znaku?

Který systém píše diakritiku až po znaku?
« kdy: 07. 12. 2023, 10:40:50 »
Zdravím, mám zvídavý dotaz: netušíte nevíte někdo, jakým způsobem lze za normálních okolností (tzn. bez nějakých speciálních nástrojů) napsat diakritické písmenko (např. obyčejné dlouhé a → á) tak, že nejdřív se napíše a a až pak čárka ´

U nás je běžně á na české klávesnici na klávese 8. Taky lze totéž písmeno napsat tak, že se bouchne nejdřív čárka (klávesa =) a pak obyčejné malé a a vznikne z toho á. Oba jsou to jak vzhledově, tak binárně naprosto identické znaky (aspoň ve Windows).

Proč se ptám: řešil jsem převod dat z jedné databáze do druhé (Oracle→MSSQL) a narazil jsem na slovo „Oznámení“ (jako součást názvu souboru), které v databázi bylo dvakrát. Je nad tím vytvořený unique index s výběrem několika sloupců a došlo k tomu, že ve zdrojové databázi byly všechny hodnoty dvakrát, akorát to jméno souboru se lišilo právě v tom, jakým způsobem je napsané to „Oznámení“. Oracle to nebral jako duplicitu, MSSQL to jako duplicitu vzal, protože mě nenapadlo, že musím dát Collation s vlastností „WS - width sensitive“ (to se v našem prostředí běžně nedělá). Tedy já vím, jak ten problém vyřešit, ale co je mi záhadou, je, jak mohl někdo tyhle znaky do té databáze uživatelskou cestou dostat. Neznám aplikační logiku, která do té databáze strká data, a je to irelevantní, téměř jistě tam prostě dochází k uploadům souboru, ty se ukládají do databáze (čert to vem) a jméno souboru se k nim připíše spíš tak jako pro pořádek (reálně to jméno souboru nikde na filesystemu už nefiguruje, aby se na něj něco odkazovalo nebo tak).

A teď jak to jméno souboru (resp. ta část jména vyjádřená slovem „Oznámení“) vypadala v té druhé binárně neidentické verzi: no, takto: „Oznámení“.

Jakkoli to vypadá stejně, stejné to není. Když jsem si to rozklíčoval do hexa, zjistil jsem, že existuje sada speciálních diakritických znaků (Combining Diacritical Marks), což jsou diakritické znaky platící pro znak před nimi (aneb v případě čárky je to „čárka nad tím, co je před tím“). Takhle lze jakýkoli z těchto diakritických znaků napsat nad jakýkoli jiný znak (asi kromě jakéhokoli znaku z této sady), takže lze vyrobit třeba slovo „eͫnͤcͯoͥdͨeͦ“ ;) Takže zatímco takový „Pěťovníček“ má v UTF16 22 bajtů, tak „Pěťovníček“ jich má 28. A když bude v MSSQL Collation bez width sensitive, tak to budou pro ten server duplicitní řetězce (pokud se to dá do sloupce s podporou unicode znaků, tedy např. nvarchar - když jsem to dával do varchar, rozdělilo to ten diakritický znak od toho běžného a vznikly dva, takže se duplicita nekonala).

Já to takhle napsal za pomoci dencode.com/string/hex, ale mě zajímá, jestli nevíte, jak (v jakém OS?) se to dá napsat "normálně", bez dopomoci nějakých takovýchto fíglů.


Re:Který systém píše diakritiku až po znaku?
« Odpověď #1 kdy: 07. 12. 2023, 10:53:45 »





Tak dokonce jdou kombinovat i ty znaky  ͪͪͪͪͪͪ - tenhle má v UTF16 12 bajtů, je to h nad h nad h nad h nad h nad h :D

Re:Který systém píše diakritiku až po znaku?
« Odpověď #2 kdy: 07. 12. 2023, 11:07:02 »
Jmenuje se to "UNICODE NORMALIZATION FORMS": https://unicode.org/reports/tr15/

Re:Který systém píše diakritiku až po znaku?
« Odpověď #3 kdy: 07. 12. 2023, 12:18:33 »
unicode normalization forms je proces, jak právě ty unicode composition forms převést na jednotný tvar. Lze hledat i pod termínem unicode equivalence.

V praxi to vždy na vstupu převádíme buď do tvaru fully composed (NFC/NFKC, když to jde, sdruž to do jednoho znaku; šetří to místo, ale je to problematické v čase, protože zkrácené varianty se objevují postupně) nebo fully decomposed (NFD/NFKD, vždy to rozlož; dost místa navíc, ale nedělají nám problémy v Unicode specce při přidávání nových znaků).

Např. Mac OS dělá normalizaci při ukládání souborů na samba server, kdy název souboru na vstupu umí přepsat na ekvivalentní ale binárně jinou variantu, což pak vznikají blbé chyby.

Normalizaci může dělat jakýkoliv SW na cestě, který zpracovává znaky. Např. hodně composed nám chodí z Větnamu a třeba strikntě NFD zase produktují FR státní systémy. Vinu hledej v klávesnici, různé národní klávesnice to dělají různě.

Z pohledu databáze je za mě nutné vždy na vstupu provést normalizaci (ideálně přes NFD/NFKD), unique indexy na unicode je časovaná bomba a je nutné investovat dost času právě do správné normalizace a její vynucení, to není vůbec triviální. Pokud databáze je jen uložiště textů, tak si problémů ani nemusíš nikdy všimnout, protože text se načte, uloží, přepíše, pokud ale potřebuješ data zpracovávat (řadění, třídění, hledání), už to dělá velké problémy, stejně tak dělá problémy, když část zpracování děláš až na klientu, protože se k tomu musí chovat stejně.

Re:Který systém píše diakritiku až po znaku?
« Odpověď #4 kdy: 07. 12. 2023, 13:56:04 »
Postup psaní “nejprve znak, potom diakritika” používají systémové klávesnice v iOS. Ale jak už psal Tomáš, samotné pořadí jak se to napíše na klávesnici neznamená že to tak je ve výstupním textu “zakódované”.


Re:Který systém píše diakritiku až po znaku?
« Odpověď #5 kdy: 07. 12. 2023, 15:16:28 »
Spíš bych to viděl, že to zprznila nějaká knihovna, která převáděla texty z jednoho kódování do jiného nebo nějaká chybná konfigurace kódování na straně serveru/klienta a že to bude něco co v té databázi už je pěknou řádku let.

Já jednou migroval MySQL, kde byly stringy v UTF-8 zakódované do UTF-8, tedy místo jednoho klasického 2B znaku to bylo zakódované do 2B+2B (a ne, UTF-16 to nebylo :) ).

Přesnou příčinu jsem ani nehledal, protože na tom systému bylo všechno zpatlané - systémové locales nějaké, do init skriptu pro mysql doprasen export LC_ALL, v PHP co se připojoval k mysql zase vynucené latin2 kódování a kdykoliv se něco z toho zkusilo změnit, tak to začalo požírat data a nakonec bylo nejjednodušší to komplet zmigrovat a pročistit.

Re:Který systém píše diakritiku až po znaku?
« Odpověď #6 kdy: 07. 12. 2023, 15:21:27 »
Jabko. Nevím jak iOS, já při tom přistihl Masox.

To si jednou takhle stěžoval nejmenovaný kolemjdoucí, že mu v IMAPovém inboxu zmizel starý obsah složky "odeslaná pošta". Server je Linux. Všiml jsem si, že někteří IMAP klienti (MUA) pojmenovávají well-known složky na serveru stručnými anglickými názvy: např. "Sent", "Junk" apod. a lokalizované názvy jsou otázkou uživatelského rozhraní.
Ne tak Apple Mail. Samozřejmě jablíčkáři používají zásadně nativní příbalové appky, protože "jabko je správně".
Milý Apple Mail má složku pojmenovanou v lokalizovaném tvaru přímo na serveru - a protože Unicode end to end, tak to klapne. Takže "Odeslaná pošta" přímo na storagi pod IMAP serverem, Linux s tím nemá problém. Problém nastal zřejmě změnou, kdy Apple Mail původně složku pojmenoval ve "dvouznakové rozložené" variantě Unikódu, ale s určitým updatem si to rozmyslel, a ten lokalizovaný název nově vytváří a očekává v "kompaktním" kódování. Prostě přišel update, a na IMAP serveru vykvetla tatáž složka "Odeslaná pošta" podruhé. "ls" na linuxovém serveru ukázalo dvě složky s identickým názvem, čučel jsem na to jak husa na blesk. Jablečný IMAP klient ukazoval pouze jednu složku, ovšem zřejmě se mu jenom "překryly v indexu" a reálně si vybral tu nově založenou. Když jsem přestal vidět dvojitě, poslal jsem si výstup z "ls" do souboru a otevřel ho v hexa editoru, a bylo jasno.

kmarty

  • ***
  • 194
    • Zobrazit profil
Re:Který systém píše diakritiku až po znaku?
« Odpověď #7 kdy: 07. 12. 2023, 16:35:47 »
Tohle neni zavisle na systemu, jen na zpusobu vkladani znaku. I z Linuxu ti muzu napsat:
Kód: [Vybrat]
$ echo "příliš žluťoučký kůň úpěl ďábelské ódy" | wc -c
54
$ echo "příliš žluťoučký kůň úpěl ďábelské ódy" | wc -c
69
$

resp.
Kód: [Vybrat]
$ echo "příliš žluťoučký kůň úpěl ďábelské ódy" | xxd
00000000: 70c5 99c3 ad6c 69c5 a120 c5be 6c75 c5a5  p....li.. ..lu..
00000010: 6f75 c48d 6bc3 bd20 6bc5 afc5 8820 c3ba  ou..k.. k.... ..
00000020: 70c4 9b6c 20c4 8fc3 a162 656c 736b c3a9  p..l ....belsk..
00000030: 20c3 b364 790a                            ..dy.
$
$ echo "příliš žluťoučký kůň úpěl ďábelské ódy" | xxd
00000000: 7072 cc8c 69cc 816c 6973 cc8c 207a cc8c  pr..i..lis.. z..
00000010: 6c75 74cc 8c6f 7563 cc8c 6b79 cc81 206b  lut..ouc..ky.. k
00000020: 75cc 8a6e cc8c 2075 cc81 7065 cc8c 6c20  u..n.. u..pe..l
00000030: 64cc 8c61 cc81 6265 6c73 6b65 cc81 206f  d..a..belske.. o
00000040: cc81 6479 0a                             ..dy.
« Poslední změna: 07. 12. 2023, 16:38:44 od kmarty »

Re:Který systém píše diakritiku až po znaku?
« Odpověď #8 kdy: 07. 12. 2023, 16:50:31 »
Motáte do sebe dvě nezávislé věci. Jenda je, jak se texty zadávají na klávesnici. Na klasické hardwarové klávesnici se typicky nejprve píše diakritické znaménko a pak teprve znak. Na Androidu se znaky s diakritikou obvykle píší tak, že se déle podrží příslušný znak, čímž se rozbalí nabídka znaků s diakritikou, ze které si uživatel vybere. Ale jsou i jiné způsoby. Na iOS se znaky zadávají tak, že se zadá příslušný znak bez diakritiky a teprve pak zadáte diakritické znaménko, napsaný znak se pak nahradí.
To jsou ale jen způsoby zadání znaků na klávesnici a nijak to nesouvisí s tím, co máte v datech.
To, co máte v datech, je to, že v Unicode existují různé zápisy stejných znaků. Třeba znak „á“ může být zapsán jako znak „malé A s čárkou“, kód U+00E1. To samé lze ale zapsat také jako kombinaci znaků „malé a“ U+0061 a „modifikátor – čárka nad znakem“ U+0301. A je definován proces normalizace, při kterém se tyto různé zápisy převádějí na definovaný základní zápis. (Aby to nebylo tak jednoduché, je těch postupů víc, detailně to popsal _Tomáš_). Ten druhý způsob popisuje znak tak, jak vzniká – jako spojení dvou znaků. První způsob (jeden znak) popisuje znak tak, jak bývá typicky reprezentován v jiných znakových sadách, tedy jako jeden samostatný znak.

Pokud se text má používat k něčemu jinému, než zobrazení (např. vaše kontrola unikátnosti, vyhledávání), je potřeba texty před uložením normalizovat (vždy stejným způsobem) a stejně normalizovat např. parametry vyhledávání.

Re:Který systém píše diakritiku až po znaku?
« Odpověď #9 kdy: 07. 12. 2023, 19:51:12 »
Už tu přičina a řešení byl zmineno, řešením je ukládat texty normalizované. příčina byl asi ukládání uživatelského vstupu. nebo při řažení použít normalizaci pokaždé hceš li zachovat původní text

_Jenda

  • *****
  • 1 606
    • Zobrazit profil
    • https://jenda.hrach.eu/
    • E-mail
Re:Který systém píše diakritiku až po znaku?
« Odpověď #10 kdy: 07. 12. 2023, 23:33:11 »
S tím jsem si dobře užil. Uživatel (používal OS X) mi nahrál do WordPressového webu soubory s jednou normalizací a pak v editoru na ně odkazoval s druhou normalizací. Celé to bylo opepřené tím, že jemu to fungovalo, podle všeho Safari normalizuje požadavky nebo tak něco.

Doporučuji přečíst článek, který normalizace a další důležité věci vysvětluje https://tonsky.me/blog/unicode/

Re:Který systém píše diakritiku až po znaku?
« Odpověď #11 kdy: 08. 12. 2023, 11:55:10 »
Díky za podnětné příspěvky, vypadá to na to jabko. Já jsem jen správce databáze, ne dat v databázi, o tom rozhodují (a řeší to) jiní, ale navrhnu jim tu normalizaci, aby se tomu dalo vyhnout. Z mého DB pohledu bude nejsnazší v té Collation nezapínat width sensitivitu, ono je to pak vy*akuje samo. Nevěřím tomu, že to budou chtít aplikačníci řešit, na to je už trochu znám ;).

…"ls" na linuxovém serveru ukázalo dvě složky s identickým názvem, čučel jsem na to jak husa na blesk.…

Vybavila se mi kolegovo příhoda, kdy v Putty tuším na AIX (nebo možná HP-UX, no klasický linux to nebyl) serveru přejmenovával název datového souboru Oracle databáze. A samozřejmě to udělal stylem ← ← ← Del 0 → → → Enter - a až po tom odentrování mu došlo, že to asi nebyl dobrý nápad :). No, přejmenovat následně ten soubor živé databázi byla docela zajímavá taškařice, ale nějak to udělal (ty kurzorové šipky na klávesnici se staly součástí souboru a taky mu tam ve finále vznikly dva soubory „jakoby téhož“ jména - používal nějaký zápis, který to byl schopný převádět na nějaké to hexa vyjádření znaků a podobně).