Vinnaren i pepparkakshustävlingen!
  • 1
  • 2
2021-11-25, 20:08
  #1
Medlem
hashs avatar
Jag är novis på Java, så jag hoppas ni har överseende.

Läste på nätet att en String i Java använder by default UTF-16 som encoding.

Om jag t ex konkatenerar en sträng följande.
Kod:
String myString = "test1 " + "test2";

I detta läget har alltså myString encoding UTF-16.
Om jag nu vill ha min sträng som en ISO-8859-1, gör jag följande...
Kod:
Charset iso88591charset = Charset.forName("ISO-8859-1");
byte[] iso88591bytes = myString.getBytes(iso88591charset);
String newMyString = new String ( iso88591bytes, iso88591charset );

Nu bör alltså min nya variabel newMyString var ISO-8859-1 encodad, eller har jag fel?

Vad händer med min String om jag gör följande efteråt?
Kod:
String newString3 = newMyString.replaceAll("2", "3");

Kommer newString3 var UTF-16 nu eller behålla ISO-encodingen?
Osäker på om newString3 räknas som en ny String och därför blir UTF-16?

Någon som kan bringa klarhet i detta?
Citera
2021-11-25, 20:42
  #2
Avstängd
realFEZs avatar
Citat:
Ursprungligen postat av hash
Jag är novis på Java, så jag hoppas ni har överseende.

Läste på nätet att en String i Java använder by default UTF-16 som encoding.

Om jag t ex konkatenerar en sträng följande.
Kod:
String myString = "test1 " + "test2";

I detta läget har alltså myString encoding UTF-16.
Om jag nu vill ha min sträng som en ISO-8859-1, gör jag följande...
Kod:
Charset iso88591charset = Charset.forName("ISO-8859-1");
byte[] iso88591bytes = myString.getBytes(iso88591charset);
String newMyString = new String ( iso88591bytes, iso88591charset );

Nu bör alltså min nya variabel newMyString var ISO-8859-1 encodad, eller har jag fel?

Vad händer med min String om jag gör följande efteråt?
Kod:
String newString3 = newMyString.replaceAll("2", "3");

Kommer newString3 var UTF-16 nu eller behålla ISO-encodingen?
Osäker på om newString3 räknas som en ny String och därför blir UTF-16?

Någon som kan bringa klarhet i detta?
Jag orkar inte riktigt hänga med här, men vad är det du vill göra egentligen? Det känns som det går att göra lite smidigare än så här.
Citera
2021-11-25, 21:04
  #3
Medlem
hashs avatar
Citat:
Ursprungligen postat av realFEZ
Jag orkar inte riktigt hänga med här, men vad är det du vill göra egentligen? Det känns som det går att göra lite smidigare än så här.

Jag kan förstå att du uppfattar det lite flummigt.
Grejen är den att jag inte förstår hur Java hanterar String klassen med encoding.
Jag har läst mig till på nätet att String klassen använder UTF-16 som standard.

Mitt problem är att jag vill skriva ut en payload med ISO-8859-1, men det slutar alltid med UTF-8.
Vilket jag misstänker är faktiskt operativsystemets "locale", i en Redhat Linux.

Jag vill inte ha UTF-8 utan en payload med ISO-8859-1.

ISO-8859-1 krävs för att jag vet att mottagare-systemet, ett Mainframe system som inte klarar något annat.

Jag har upptäckt att när jag kalkylerar ut HMACSHA256, så blir den olika beroende på encoding.

Sen mitt andra problem är att jag suger på Java
Min fundering är, så fort jag ändrar innehållet i en String i java med innehåll, kan encodingen ändras?
__________________
Senast redigerad av hash 2021-11-25 kl. 21:08.
Citera
2021-11-25, 21:33
  #4
Avstängd
realFEZs avatar
Citat:
Ursprungligen postat av hash
Jag kan förstå att du uppfattar det lite flummigt.
Grejen är den att jag inte förstår hur Java hanterar String klassen med encoding.
Jag har läst mig till på nätet att String klassen använder UTF-16 som standard.

Mitt problem är att jag vill skriva ut en payload med ISO-8859-1, men det slutar alltid med UTF-8.
Vilket jag misstänker är faktiskt operativsystemets "locale", i en Redhat Linux.

Jag vill inte ha UTF-8 utan en payload med ISO-8859-1.

ISO-8859-1 krävs för att jag vet att mottagare-systemet, ett Mainframe system som inte klarar något annat.

Jag har upptäckt att när jag kalkylerar ut HMACSHA256, så blir den olika beroende på encoding.

Sen mitt andra problem är att jag suger på Java
Min fundering är, så fort jag ändrar innehållet i en String i java med innehåll, kan encodingen ändras?
Ahaja. Det låter som riktigt gamla saker det här. Det var länge sen jag pysslade med Java och jag kan inga detaljer kring encodingen där. Vad menar du med "skriva ut en payload"? Hur gör du det?
Citera
2021-11-25, 21:42
  #5
Medlem
Emma18s avatar
Det stämmer att Java ibland använder UTF-16 internt för att lagra strängar, exakt hur det lagras beror på vilket Java-version du kör och faktiskt vad strängen innehåller. Detta är dock ingenting du enkelt kan ändra, och inte någonting du behöver ändra. Din extra kod förändrar inte hur java hanterar strängen internt, utan det enda du gör är att exportera innehållet i din sträng till en byte-array för att sen importera det till en sträng igen.

Om du vill skriva ISO-8859-1 till en textfil kan du göra till exempel:

Kod:
File file = new File("c:\\TEMP\\file.txt");
BufferedWriter writer = Files.newBufferedWriter(file.toPath(), Charset.forName("ISO-8859-1"));
writer.write(myString);

Annars så i ditt exempel så skriver du ju redan texten till en byte-array med hjälp av:

Kod:
Charset iso88591charset = Charset.forName("ISO-8859-1");
byte[] iso88591bytes = myString.getBytes(iso88591charset);
Denna byte-array kan du ju sen göra vad du vill med, skriva till fil eller skicka till mottagaren.

I teorin går det att ändra hur Java lagrar strängar internt, men även om du gjorde det skulle det inte påverka vad som händer när koden körs, utan bara internt. I modern Java lagras faktiskt strängarna som ISO-8859-1 så länge de tecken som finns i strängen finns i den teckenuppsättningen men det gör inte att filskrivning sker med ISO-8859-1.
__________________
Senast redigerad av Emma18 2021-11-25 kl. 21:47.
Citera
2021-11-25, 21:50
  #6
Medlem
hashs avatar
Citat:
Ursprungligen postat av realFEZ
Ahaja. Det låter som riktigt gamla saker det här. Det var länge sen jag pysslade med Java och jag kan inga detaljer kring encodingen där. Vad menar du med "skriva ut en payload"? Hur gör du det?

Payload är egentligen bara filens innehåll, behöver skriva ut den till en EDI-process med rätt encoding.

Men som sagt, jag förstår inte hur Java String klass fungerar.
Kan encoding förändras så fort man gör en förändring i en String variabel?
Citera
2021-11-25, 23:05
  #7
Medlem
Citat:
Ursprungligen postat av hash
Payload är egentligen bara filens innehåll, behöver skriva ut den till en EDI-process med rätt encoding.

Men som sagt, jag förstår inte hur Java String klass fungerar.
Kan encoding förändras så fort man gör en förändring i en String variabel?

Vilken del av dokumentationen för String är du osäker på? En String är immutable vilket betyder att innehållet aldrig kan ändras. Däremot kan man förstås ändra en variabel så att den refererar en annan sträng (om variabeln inte är final), vilket görs med en assignment operator.

https://docs.oracle.com/javase/7/doc...ng/String.html
Citera
2021-11-26, 07:16
  #8
Moderator
vhes avatar
Citat:
Ursprungligen postat av hash
Men som sagt, jag förstår inte hur Java String klass fungerar.
Kan encoding förändras så fort man gör en förändring i en String variabel?

Nu var det 20 år sedan jag kodade Java, men inte tänker jag låta total okunskap stoppa mig från att posta!

Jag tror du tänker på String-klassen fel. Tänk inte "encodad sträng", tänk "abstrakt objekt som representerar vilka tecken som helst". Poängen med klassen är att den skall kunna hantera godtyckliga unicodetecken (inte tecken i en viss encoding - bara tecken). Det är när du behöver serialisera din sträng som du behöver fundera på encoding. Så, m.a.o., gör all den manipulation av strängen du behöver, och när det är dags dumpa ut den som en payload som du encodar den enligt Emmas mall ovan.

Eventuella checksummor/kryptografiska signaturer görs på den encodade datan.
Citera
2021-11-26, 09:52
  #9
Medlem
Enterprises avatar
Citat:
Ursprungligen postat av vhe
Nu var det 20 år sedan jag kodade Java, men inte tänker jag låta total okunskap stoppa mig från att posta!

Jag tror du tänker på String-klassen fel. Tänk inte "encodad sträng", tänk "abstrakt objekt som representerar vilka tecken som helst". Poängen med klassen är att den skall kunna hantera godtyckliga unicodetecken (inte tecken i en viss encoding - bara tecken). Det är när du behöver serialisera din sträng som du behöver fundera på encoding. Så, m.a.o., gör all den manipulation av strängen du behöver, och när det är dags dumpa ut den som en payload som du encodar den enligt Emmas mall ovan.

Eventuella checksummor/kryptografiska signaturer görs på den encodade datan.
Alltså, String-klassen är i princip en "svart låda" där man inte behöver bekymra sig om hur data lagras "under motorhuven"?
Citera
2021-11-27, 17:47
  #10
Medlem
kjellbrels avatar
Citat:
Ursprungligen postat av hash
Någon som kan bringa klarhet i detta?
Vet inte om du tycker att detta klarnat via de svar du fått, då de ibland varit otydliga och delvis missvisande.

Javas fundamentala datatyp för detta, char, representerar alltid Unicode. Ingenting annat. Javas String likaså. Glöm encodingformat helt här. (*1)

När man av något skäl vill hantera tecken utanför dessa typers runtimelagring, i ex en fil, en nätverksström eller annat, så behöver man omvandla dessa till ett transportformat. Först här kommer encoding och olika format in i bilden.

De metoder som omvandlar tecken till ett transportformat eller tvärtom omvandlar alltså från Unicode till ett encodingformat eller tillbaka. Vissa där man anger format via metodparametrar och vissa med defaultformat. Detta är väl dokumenterat i javadoc:en för Java Core API och väl värt att kolla upp. Typen Charset används för encodingformat.

Encodingformatet UTF-16 är förvisso väldigt nära Unicode i sin lagring, men det är fortfarande 2 olika saker.

Med detta som grund så kan vi gå igenom dina exempel steg för steg:

Citat:
Ursprungligen postat av hash
Läste på nätet att en String i Java använder by default UTF-16 som encoding.

Om jag t ex konkatenerar en sträng följande.
Kod:
String myString = "test1 " + "test2";

I detta läget har alltså myString encoding UTF-16.
Nej, den använder alltid Unicode. (*1)

Citat:
Ursprungligen postat av hash
Om jag nu vill ha min sträng som en ISO-8859-1, gör jag följande...
Kod:
Charset iso88591charset = Charset.forName("ISO-8859-1");
byte[] iso88591bytes = myString.getBytes(iso88591charset);
String newMyString = new String ( iso88591bytes, iso88591charset );
Din myString är Unicode.
Anropet getBytes() ovan omvandlar från Unicode till angivet format.
Din iso88591bytes är en array av bytes (inte tecken längre) i encondingformatet "ISO-8859-1". (*2)
Konstruktorn ovan för String omvandlar indata från dess encodingformat till Unicode.
Din newMyString är Unicode.

Citat:
Ursprungligen postat av hash
Vad händer med min String om jag gör följande efteråt?
Kod:
String newString3 = newMyString.replaceAll("2", "3");
DIn newString3 är Unicode.

(*1): De är specificerat i Javas språkdefinition att det är Unicode som representeras i char och String. Även om det är teoretiskt möjligt att enl specifikationen fullfölja definitionen och ändå lagra tecken internt i en String i något annat format, så spelar det ingen roll. Alla metoder som jobbar med typen char i String, jobbar med Unicode i sitt gränsssnitt.

(*2): Detta förutsatt att plattformen accepterade det format du angav. Vissa format måste stödjas enl standarden, bland annat ISO-8859-1.
Citera
2021-11-30, 02:16
  #11
Medlem
Citat:
Ursprungligen postat av kjellbrel
Encodingformatet UTF-16 är förvisso väldigt nära Unicode i sin lagring, men det är fortfarande 2 olika saker.

Med Unicode menar du då UTF-32? Det är inte lika vanligt som UTF-8 och UTF-16 som är de två vanligaste formaten. Javastandarden anger förresten att UTF-16 ska användas av Java förutom i Character-klassen och vissa andra undantag.
Citera
2021-11-30, 16:05
  #12
Medlem
kjellbrels avatar
Citat:
Ursprungligen postat av Hominem
Med Unicode menar du då UTF-32? Det är inte lika vanligt som UTF-8 och UTF-16 som är de två vanligaste formaten. Javastandarden anger förresten att UTF-16 ska användas av Java förutom i Character-klassen och vissa andra undantag.
Nej, jag menar definitivt inte UTF-32.

Läste du min (*1) från föregående inlägg? Jag ville hålla isär vad man ser och är garanterad när man använder char och String i Java från implementationsdetaljer i JVM:en.

Som utvecklare ser du enbart Unicode (Unicode code points) i typen char i Java (och därmed samtliga andra core API-anrop som jobbar med den typen i sina metoder, ex i String, Character mm). Eftersom Unicode vuxit över sin ursprungliga maxstorlek (16 bitar) så har det blivit andra problem med att char är 16 bitar (surrogate pairs för att beskriva enskilda tecken), men det är en fråga för sig.

Som utvecklare hanterar man encodingformat först när man omvandlar från char till transportformat eller tillbaka.

Unicode -> (encode) -> UTF-x/ISO...mm -> (decode) -> Unicode

Det är viktigt ur den här synpunkten att se char (Unicode) för sig och transportformat (UTF-x mm) för sig och veta att man själv i detta läge gör encoding/decoding för omvandla mellan dem och att man själv ansvarar för vilket encodingformat som skall användas. Detta gäller även om encodingformatet är identiskt med källan. Även om de är helt identiska så är de i två olika format, som representerar olika saker.

Som utvecklare skall man enbart bry sig om att man har Unicode code points i char helt oavsett hur JVM:en är implementerad.

TS försökte påverka lagringsformatet för innehållet i String. Mina förtydliganden var till för att klargöra varför detta inte fungerade.
Citera
  • 1
  • 2

Stöd Flashback

Flashback finansieras genom donationer från våra medlemmar och besökare. Det är med hjälp av dig vi kan fortsätta erbjuda en fri samhällsdebatt. Tack för ditt stöd!

Stöd Flashback