I hate Unicode!

Par hete ugy dontottem, ideje a 20+ eve C-ben irt unixos (IRIX/AIX alatt is mukodo) konzolos levelezoprogramomat ujrairni, elsosorban az unicode es html support miatt. A regi verzio latin2-be konvertalt mindent (iconv), a C-ben irt minimal html parserem meg tobbszor segfaultolt mint mukodott, de sose volt hangulatom kidebuggolni :)

Mivel C-ben a stringkezeles meglehetosen kenyelmetlen, unicode-rol nem is beszelve, meg amugy is inkabb pythonozok mostanaban, igy py3-ra esett a valasztas. Ma mar ugyse szamit az eroforras annyira, mint 20+ eve.

Az alapokat (terminal i/o, mailek indexelese, headerek parsolasa) hamar osszeraktam, reszben mas projektjeimbol (mail dolgokat a pl. spamszurobol) osszeollozva. Ra is engedtem egy jo kis spam-gyujtemeny mailboxra, es akkor ert a meglepi: szetesett az egesz.

Persze annyira nem kellett volna meglepodnom, de megis csak ekkor tudatosult, hogy hiaba a fix karakterszelessegu font es terminal (iTerm2 amugy), nem minden unicode karakter ugyanolyan szeles. Vannak kivetelek, nem is keves, nem csak a szines emojik, hanem pl. a japan karakterek, nyilak stb, es elegge random poziciokban...

Szerencsere mas mar osszeszopta a nagyjat:  https://github.com/jquast/wcwidth

de azert ez se kezel le minden baromsagot... mert van olyan is, hogy fogsz 2 emojit es raksz koze egy joiner karaktert, es ha olyan kedve van a megjelenitonek (fuggoen az OS, a terminal es a font unicode verziojatol) osszerakja oket egybe, de lehet hogy nem...

aztan ami leginkabb kiakasztott: vannak olyan speci betuk(!) 0x1F1E6-tol amik orszagkodokat alkothatnak, pl. kiraksz egy ures zaszlo emojit aztan egy D es egy E betut es lesz az egeszbol egy nemet zaszlo ikon. persze csak ha a font epp szereti ezt a kombot.

meg van szinesito modifier karakter, amit ha egy sima egyszinu szimbolum utan irsz akkor szines emoji lesz belole es dupla szeles is egyben. na nem mindig, csak ha olyan kedve van...

a lathatatlan, zero-width modifierekrol (zwsp, zwj stb) nem is szolva. szoval nagyon nem konnyitik meg egy terminal app fejleszteset...

Hozzászólások

Csalodtam. Nem C. Kurvul a vilag. :D

Every single person is a fool, insane, a failure, or a bad person to at least ten people.

hat teny, hogy a C gyorsabb volt, 4-8x de azert 100k level beparsolasat 5-8 masodperc alatt is ki lehet birni :)

eredeti C kod:  real    0m1.310s

python 3.10: LOADED 96750 emails in 8.726 seconds

pypy 3.10:  LOADED 96750 emails in 4.882 seconds

mondjuk ez igy nem fair, mert a C kod megjeleniteskor parsolta a headereket, a py verzio meg indexeleskor... kivettem ideiglenesen a parsolast, ugy 3s alatt lefutott a pypy-vel:  LOADED 96750 emails in 3.076 seconds  de meg ugy is kb 2-3x gyorsabb a C

bar ilyen egyszeru lenne :)

cuda eseten ezeket kell osszehaongolni (ez nem desktop, hanem fejleszto gep, server amugy):

- cuda kernel driver  (ez kernel verziotol es kartya tipustol is fugg valamennyrie)

- cuda lib-ek (ennek a driverrel kell kompatibils verziojunak lenni)

- cudnn lib-ek (nyilvan cuda lib fuggo, de nem sok verzio elerheto, elegge bekorlatozza a lehetosegeket)

- tensorflow es pytorch, ami pedig a cudnn-tol (es a cuda libektol is) fugg, foleg a tf nagyon maceras

es ezeket ugye kulonbozo forrasasbol lehet beszerezni, driver van ubi repoban, cuda lib nvidia repo, cudnn csak developer acc-al erheto el a tf/pt pedig pypi-rol jon jobb esetben, vagy forditani kell forrasbol

altalaban egy apt upgrade utan min fel nap ezeket osszelegozni ujra :(

 

a fo gond hogy az nvidia nyomja a legujabb verziokat, foleg a cudnn-bol, gyorsan el is tunteti a regieket. ugyanakkor a tf/pt le van maradva, most a 11.8 cuda korul tartanak mikozben a cuda mar 12.1-nel (es 11.x a 12.x-el nem kompatibilis)

ubi repoban meg tobb evvel ezelotti cuda es driverek vannak, igy azt is forditani kell altalaban (a drivert legalabbis, a lib jon nvidia repobol de az meg a fel ubuntut is lecsereli a sajat verziojukra).

Én tapasztalataim szerint VGA driver verzió === CUDA driver verzió === CUDA kliens könyvtár === hozzá tartozó header filek együttállása az optimális.

Lehet hogy az utóbbi másfél-két évben ez változott, de amikor én játszottam hálósat akkor ennek egész szigorúan teljesülnie kellett különben jött a PRÁK és elvitte a programot magával.

 

---

Editke: Árpi szebben és tényszerűbben leírta, nekem ez már szerencsére ködös.

na nezzuk!

45k spam level teljes (mime+html) parsolasa (mindegyikkel 3x mertem es a legjobb idot neztem, 5.8Ghz i9+ddr5 gepen):

python 3.10.6:  [45034]  LOADED 45035 emails in 44.992 seconds

python 3.11.4:  [45034]  LOADED 45035 emails in 36.064 seconds

python 3.12b2: [45034]  LOADED 45035 emails in 42.608 seconds

erdekes hogy a 3.12 lassabb lett :)  asszem atallok 3.11-re egyelore, koszi a tippet

Szerkesztve: 2023. 06. 18., v – 18:34

Bonyolult lett a világ, én is így látom. Nem véletlenül kerestem én is új utat magamnak sok évnyi C-ben való problémamegoldás után.

Most ennek Rustban állnék neki, amely utf8 alapból, viszont az általad írt zéró helyet foglaló karakter meg hasonlók miatt például ez a crate tuti játszana: https://crates.io/crates/console

Számodra viszont nem megoldás, mert az LLVM (clang) nem viszi az AIX-ot, így oda nem fordul. Majd egyszer, ha a gccrs projekt használható lesz (gcc-14?).

nezegettem mar a rust-ot parszor de nekem valahogy nagyon nem jott be...

mondjuk ez pont egy jo projekt lenne uj nyelvet tanulni (anno a C-t is ezzel tanultam, akkor dos-os pascalbol irtam at), de oreg vagyok mar hozza :)

raadasul a kodbazis nagy resze kozos a spamszurommel, sok javitas amit most csinaltam a parserekben ott is hasznos. azt meg nem tudnam rust-ba atirni, a pytorch miatt...

aix mar nincs, sem irix, csak 20 eve meg azon futott, most mar eleg a linux/macos...

a C-ben irt minimal html parserem meg tobbszor segfaultolt mint mukodott, de sose volt hangulatom kidebuggolni :)

Esetleg felajánlhatom a YTFE HTML parserét? FreePascalban van, de lehet belőle object fájlt csinálni és behúzni a C-s programba. Vagy libet és akkor meghívogatni. Vagy átírni C-be. :P

megnezhetem erdekesseg keppen, de gondolom az a YT html-jere van kihegyezve, ami vszinu valid...

probaltam sokfele html2text libet/megoldast, de egyik se igazan jo a spam emailek html reszehez, mert azok trukkoznek direkt rossz szintaktikaval, hogy megkeruljek a szuroket...  eleve az email text/html partja egy kulon allatfaj, probaltam webkittel is kirendereltetni de nem volt jo. gondolom az outlookban egy elcseszett ie6-szeru html dll-t hasznalnak, a tobbi levelezo app meg probal azzal kompatibilis lenni...  tele van legacy hackekkel (pl. a css-t berakja egy kommentbe, hogy amelyik program nem ismeri az atugorja), meg olyan uj hackekkel mint a hidden preview, ami azt hasznalja ki, hogy az appok previewkor a style-t nem veszik figyelembe, csak amikor megnyitod a levelet, es igy kulonbozo szoveget tudnak mutatni. meg tele van ie verzio-fuggo if-ekkel az egesz.

amugy a pythonban irt parserem (amit eredetileg a spamszurohoz irtam sok eve) mar egesz jol elboldogul, masfel hetnyi javitgatas utan... es az egesz kb 2 oldalnyi kod csak. majd lehet irok arrol is 1-2 blogposztot, hogy milyen szivasok vannak az atgondolatlan html szintaktikaval :)

ez is gyonyoru, nem?

<style type="text/css" style="display:none">
/*<![CDATA[*/
<!--
p
        {margin-top:0;
        margin-bottom:0}
-->
/*]]>*/
</style>

Nem, nem a YT HTML-jére van kihegyezve, általános parsert írtam, ami az invalid kódok nagy részét is megeszi. Hogy neked jó lesz-e, azt nem tudom. (A YT HTML-je amúgy egyáltalán nem valid, tele van tákolással, hákolással, gányolással.) Egyébként nem csak parser, hanem inkább toolbox, ha az ember keresni akar a DOM-ban, stb. Ezek persze neked lehet nem kellenek; nyugodtan kihajíthatóak és akkor 30k helyett mindjárt csak 13k, ha tisztán a parser van csak.

Email-be ágyazott HTML-t nem próbáltam parse-olni vele, de ha a node-ok értelmezhetőek (függetlenül attól, hogy a W3C ajánlás szerint valid-e a szintaxisuk), akkor azt is ennie kéne.

Arról akár könyvet is lehetne írni, hogy mennyi szívás van a HTML-lel... :(

Az...gyönyörű. :/

Dobtam egy PM-et, benne a linkkel. Ha bugot fogsz benne, report plz.

Köszi a kódot, meg a review-t/bugreportot. Ahogy levélben is írtam, a style/script tag-ek kommentjeiben a zárótag feldolgozása az bug, amit nemsoká' javítok, a többivel nem lesz gáz. Illetve a

<span style="font-family: "playfair display", georgia, "times new roman", serif; color: #e6007e;">

kóddal lesz, az idézőjel az idézőjelek között probléma miatt, de azzel azon túl, hogy még egy CSS parsert is írni kéne és a style attribútumra ráhúzni, nem tudnék mást csinálni; szerintem ez nem bug, mert ez már nem invalid, hanem hibás HTML (elég megnézni itt a syntax highlightert); ilyenkor vagy az attribútumot teszik aposztrófok közé, vagy benne a stringeket. Fixme.

en is gondoltam mar ra, hogy ahogy a mime parsolasnal elofordulo hibakat, ugy a html parser hibakat is "dijaznam" a spamszuroben extra pontokkal.  bar eleg megnenzi pl. a sokak altal magasztalt Zimbra is milyen okadek leveleket tud kuldeni (hibas headerek es eleg fura html part), szoval ez azert rizikos. 

amugy a legtobb gond a szarul megirt webshopok es mas webes izek altalal kuldott automatikus levelekkel van (amikor fogalmatlan phpistikek hivjak a mail() fv-t de nem kezelik le sem az ekezetek enkodolasat, az idezojelek escapeleset stb). es sajnos ezek kozott sok van, ami nem spam, de ha rajtam mulna kiszurnem szivesen :)

Mint az egyik népszerű terminál emulátor egykori társfejlesztője...

Sajna igazad van, ez a rész nagyon gáz.

A terminálok mind-mind mást csinálnak. Némelyik a szép kinézetre megy rá (melyik Unicode kombó milyen szélességben "szép", tehát annyi helyet foglal), csak arra nem gondolnak, hogy ezzel hazavágják a wcwidth() API-t, amely szerint le lehet mérni az egyes kódpontok szélességét és ezeket összeadni, ergó hazavágják az ncurses-t használó appok kinézetét is. Más terminálok meg ragaszkodnak a wcwidth()-hez, csak így meg csúnya lesz csomó glyph, és amiatt pampognak a júzerek. A Unicode csapat meg rohadtul nem vesz tudomást erről a problémakörről, és jön elő az újabb meg újabb "ötletekkel", amelyek nem kompatibilisek a wcwidth() megközelítéssel. A wcwidth() megközelítést (tehát hogy működik az összeadás ha egymás után fűzöl) pedig mindaddig nem lehet elhagyni, amíg létezik az a modell, hogy egy gridben tetszőleges pozíción felülírhatod az ottani karaktert. A terminál fejlesztők meg néznek egymásra hogy akkor most mi a f van és mit kéne csinálni, merthogy nincs jó válasz, így vagy úgy de mindenképp broki lesz.

(Ehhez képest csak hab a tortán, hogy ha mondjuk egy ilyen két betűből összerakott zászlós bigyónál pont középen jön ki a sortörés, akkor azt hogy a rákba kéne renderelni. Meg persze van ám olyan terminál, ami a soft sortörésnél is újrakezdi a parse-olást, tehát kiírsz 100 darab GB (brit) zászlót, mondjuk 81 széles a terminál, betörik és a következő sor B-vel kezdődik így rajzolja neked a BG (bolgár) zászlókat. De jó, ez nyilván a terminálban hiba, a logikai sort (hard sortörésig) egybe kell parse-olnia, de akkor is hogy jelenítse meg azt ami átível egy sortörésen?)

Megoldás: Terminálban ne akarj ennyire fancy dolgokat. A Unicode-nak hála a kalapos meg hullámos őű nem fog a rendes magyarral keveredni, erre jó a Unicode, ennél többre a terminál emuláció világában nem nagyon.

Én nem utálom a Unicode-ot, de elkezdték valóban néhányan túltolni. Ilyen nagyon csilivili zászlós és egyéb emoji karaktereket amúgy sem jó használni, mivel a legtöbb terminálfont egyszerűen nem támogatja őket, és fallback fonttal is elég nehéz megoldani, hogy mind helyesen jelenjen meg. A másik hülyeség, ami ma nagyon nagy divat, az a terminálban a ligatúrák erőltetése, ahová nagyon nem is valók, a fix szélességű fontnak, terminálos programoknak pont az a lényege, hogy minden karakter önálló, nincs feltételes összevonás. Meg amit nem értek, sokan terminálban erőltetik a képmegjelenítást (sixel, Uberzug, stb.), az is minek. Akinek ilyen ligatúrás, meg képelőnézetes csilivili kell, használ rá GUI-t, a CLI/TUI/tty/terminál nem erre való.

Amúgy nem kéne ehhez feltalálni a kereket, kellene hogy legyen rendes libnek az UTF-8 parse-olására, stringműveletekre, nehogy már neked kelljen a kereket feltalálni.

A Unicode engem is megszopatott nemrég, a StarDict CLI változatában hiába állítom be a megfelelő UTF-8 Hungarian Collation-t a helyes betűrendbe soroláshoz, és a szótárat is hiába indexelem/generálom ennek megfelelően (erre Perl-t használok), valamiért nem talál meg szavakat, mert nem stimmel a szótárprogram és a szótár betűrendbe rendezési módszere. Egyszerűen nem bírom úgy megcsinálni, hogy jó legyen. Egyelőre félretettem, mert annyi rengeteg időm nincs most ezen fetrengeni, de később visszatérek rá.

The world runs on Excel spreadsheets. (Dylan Beattie)