Sziasztok,
van egy LDAP lekérdezésem PowerShellben, ami egy UTF8 stringet ad eredményül. Az értéket be kellene állítanom környezeti változóként (SetEnvironmentVariable), viszont ott nem jó az UTF8 érték, preferáltan CP852 kellene, de a CP1250 sem rossz megoldás, ha cmd.exe-ből dolgozom fel az eredményt.
Teljesen süket vagyok a PowerShellhez a Google pedig nem a barátom: főként olyan találatok jönnek, hogyan lehet valamit UTF8-ra alakítani, illetve, a mindenféle fájlba író/olvasó funkciók "-Encoding" opcióját hozza, ami nekem most nem releváns.
PowerShell guruk, kérlek segítsetek! Köszönöm! :)
- 234 megtekintés
Hozzászólások
Milyen LDAP szerver? Active Directory vagy valami más?
Alapvetően a PowerShell (és a Windows magában is, beleértve az Active Directory-t) a sztringeket karakterenként két byte-on, UCS-2 karakterkódolással kezeli (vagy mondhatjuk UTF-16-nak is, bár nem teljesen ugyanazt jelenti). Ez igaz az environment változókra is, a tárolásuk a memóriában karakterenként két byte. Az egybyte-os kódlapok Windows alatt inkább csak egyfajta kompatibilitási réteget jelentenek, és erősen szuboptimális a használatuk bármire is. Az UTF-8 pedig a PowerShell világában egy külsőbb tárolási forma, ha file-ba vagy hálózatra írsz sztringből eredő adatot, akkor értelmezhető, hogy UTF-8-ban lesz, de a PowerShell memóriában mint sztring változó biztosan nem.
Ezért kérdéses, hogy mit is értesz az alatt, hogy "PowerShellben, ami egy UTF8 stringet ad eredményül". Ha PowerShell-ben már van egy sztring változó, és ott helyesen vannak az ékezetek, tehát pl. egy Write-Host hívás jól jeleníti meg a változó értékét, akkor ott már nincs semmi UTF-8, ott UCS-2 van. Ha viszont a Write-Host már "furcsa" karakterekkel jeleníti meg az ékezetek értékét, akkor már eleve a PowerShell-be rosszul került bele, onnan ne is dolgozz vele tovább.
Mit jelent azt, hogy cmd.exe -ből dolgozod fel az eredményt? Ott kezd problémássá válni a dolog, ha valami olyan .exe file-nak akarod mondjuk paraméterként átadni, ami nem UCS-2 alapú, hanem egybyte-os kódlap alapú. Pl. ha C nyelven írt programnak adod át, ami nem wchar_t, hanem char típussal fogadja a parancssori paramétereket, az az ilyen esetekre erősen szuboptimális. Ott könnyen elvesznek az ékezetes karakterek.
- A hozzászóláshoz be kell jelentkezni
Nem Active Directory, de jelen esetben ez látszólag nem releváns, van a PowerShell-ben egy változóm, ami ékezethelyes stringet tartalmaz. (Mellékes körülmény, hogy a létrejötte egy LDAP lekérdezés eredménye volt, az LDAP címtárban pedig eredendően egy UTF8 kódolású string van letárolva, de nekem nem fáj, ha a PowerShell "házon belül" már UCS-2-re alakította.)
A feldolgozás egy DOS batch fájlból történik, ami mindenféle DOS-os programot hívogat. (kódlap alapút) Mivel - gondolhatod - egy meglévő, 30 éve működő megoldást szeretnék kiváltani, ezért a legjobb megoldás az, ha ugyanazzal a kódolással állítom be a környezeti változót, mint amiben korábban volt.
- A hozzászóláshoz be kell jelentkezni
A PowerShell, és az abból hívott batch file, amikor még a cmd.exe futtatja, szintén UCS-2 világban van. A DOS-os .exe programba való áthívásnál történik az izgalom. Ilyenkor ha jól tudom, az ANSI kódlapra (ami nem egy konkrét dolog, hanem mindig az adott rendszertől függ, pl. magyar beállításű windows-on az 1250) próbál konvertálni UCS-2 -ről. Ha itt vannak olyan karakterek, amik nem ábrázolhatók a cél 1 byte-os kódlapon, akkor ott lesznek a problémák.
Amit meg kéne nézned: mi az ANSI kódlap az adott rendszeren, ill. a DOS-os program milyen karakterkódolást vár. Ill. annak is utána lehet nézni, hogy ez konverzió akár nem rendszerszinten az ANSI kódlappal, hanem akár session szinten is szabályozható-e, ezt most nem tudom fejből.
- A hozzászóláshoz be kell jelentkezni
Így tudsz a Windows parancssorában, illetve a Powershell parancssorban (ha nem URF-8 a kódolás - ezt a chcp paranccsal tudod lekérdezni) kiíratni:
[System.Console]::OutputEncoding = System.Text.Encoding]::GetEncoding(1250)
$text = "idejön az UTF-8 kódolású szöveg, ami lehet egy program kimenetew is"
Write-Output $text
Szerintem erre gondoltál.
- A hozzászóláshoz be kell jelentkezni
Most nem vagyok a homokozó környezet közelében, de a [System.Console] akkor is működik, ha nem kiírni akarom az értéket Write-Output segítségével, hanem beállítok egy környezeti változót?
- A hozzászóláshoz be kell jelentkezni
Elrontottam a zárójelezést, bocs. A kiegészített kód:
[System.Console]::OutputEncoding = [System.Text.Encoding]::GetEncoding(1250)
$text = "idejön az UTF-8 kódolású szöveg, ami lehet egy program kimenete is"
[Environment]::SetEnvironmentVariable("rendszerváltozó", $asciiString, "User") #így írod be változóba
Write-Output $text #ez meg csak a példa miatt volt
Elvileg jó,
- A hozzászóláshoz be kell jelentkezni
Ja ez ilyen, zseniális húzás volt a Májrkémszafttól ez az UCS2 keverés egy UTF8-as világban, azóta is megszépíti sok ember napját. Mert ők nem tudnak ám UTF8-azni, ahogy mindenki más, ki kellett találni sajátot, újra feltalálni a kereket.
“Windows 95/98: 32 bit extension and a graphical shell for a 16 bit patch to an 8 bit operating system originally coded for a 4 bit microprocessor, written by a 2 bit company that can't stand 1 bit of competition.”
- A hozzászóláshoz be kell jelentkezni
Nyilván ezt is jobban tudod, hogy mi miért és mikor történt. Anélkül, hogy esetleg utánanéznél a valóságnak és a tényeknek. Segítek: a Microsoft elég korán (korábban, mint mások) eldöntötte, hogy normálisan támogatni fogja az ékezeteket, a Windows NT 3.1 már úgy érkezett 1993-ban, hogy UCS-2 -t használ, ami az akkori Unicode szabvány szerint az összes lehetséges karaktert árbázolni tudja, anélkül hogy kódtáblák közt kéne átalakítgatni. Ebből ered, hogy Windows alatt a sztringek karakterenként 2 byte-osak. És ez még bőven az előtt volt, hogy "UTF8-as világ" (idézet tőled) lett volna, hiszen akkor még nem volt UTF-8 világ és szabvány, amikor ők már fejlesztettek és aztán ki is hoztak egy olyan terméket, ami az összes akkori karaktert ábrázolni tudta. Némi olvasnivaló: https://devblogs.microsoft.com/oldnewthing/20190830-00/?p=102823
És ha esetleg közelebbről, mondjuk fejlesztői oldalról is hozzászagoltál volna ehhez, tudnád, hogy minimális odafigyelés mellett el lehet érni, hogy jól működjenek UCS-2 mellett a C/C++ nyelven írt programok, ne vesszenek el még akkor sem sehol az ékezetek, amikor mondjuk parancssori paraméterátadás, környezeti változó átadás stb. történik, hiszen ez a fajta karakterábrázolás a kernelen belül is így van implementálva. Olvasnivaló ehhez: https://stackoverflow.com/questions/13509733/what-is-the-use-of-wchar-t… A topiknyitó kérdésben gondolom olyan programok vannak használva parancssorból, amik nem felelnek meg ennek az elvnek.
- A hozzászóláshoz be kell jelentkezni
Kieg: szintén a 16-bites (UCS2, megpatkolva UTF-16) vonatra szállt fel az Oracle, a Java, az Aix. A többiek később ébredtek, és UTF8-ra leltek.
Szerk: a wchar_t meg még az unicode előttről való, és a pontos definíciója az, hogy "platformfüggő valami, aminek az értékkészlete legalább akkora, mint a `char`-nak'
- A hozzászóláshoz be kell jelentkezni