ich lese mit Hilfe eines InputStreams eine Html-Seite in ein Byte-Array ein.
Code:
byte [] bt = new byte[10000];
inputstream.read(bt);
Im Byte-Array steht jetzt der ganze Html-Code als Ascii-Code drin. Das funktioniert wunderbar. Nur wenn ich mir jetzt das ganze als String geben lassen möchte:
-ich muss quasi einen alphanumerischen String aus einem byte[] aufbauen
-dieser String wird an einen Server gesendet, der daraus wieder ein byte[] machen muss
-die new String(byte[], "CharsetName") - Variante hat einen unleserlichen String erstellt, was aber für die Weiterverarbeitung unbedingt benötigt wird!
-mit der "byte[].toString"-Methode kann ich einen leserlichen String erstellen
habt ihr ne idee wie ich wieder zu meinen byte[] zurückkomme?
Es wäre übrigens gut, sich über die String-Repräsentation in Java schlau zu machen, da ist nämlich nix mit Bytes und ASCII, sondern char und Unicode. Und die allgemein bekannte Zeichensatzproblematik würde ich mir auch mal zu Gemüte führen.
-string wird in byte[] gewandelt um diesen zu Zippen
-der gezippt String muss zurück in string geparsed werden,
dabei muss der String Zeichen aus dem UTF8 format enthalten
[Problem] wandelt man das byte[] mittels:
string2transmit = new String(myzippedbytearray, "UTF8")
um
so erhält man nicht darstellbar Zeichen im String.
Bsp. mit String.getBytes():Pseudo:String str1 ="Ein unkomprimierter String";byte[] bytes2compress = str1.getBytes("UTF8");/* AUSGABE vor dem Zippen des byte[]
bytes2compress: [B@e48e1b
byte2compress.lenght: 26
bytes2compress.toString: [B@e48e1b
new String(bytes2compress,"UTF8"): Ein unkomprimierter String
*///Zippen des byte[]...//...byte[] compressedBytes //ergebnis des zip vorganges/* AUSGABE nach dem Zippen des byte[]
compressedBytes: [B@10385c1
compressedBytes.lenght: 16 //bspw.
compressedBytes.toString: [B@10385c1
new String(compressedBytes,"UTF8"): x?VrU?RrLN-Rp??/H-J,????C // ?= schwarze Rauten mit ?
// und ebenso diese allseitsbekannten leeren Quadrate
*/
rückgängig machen- geht das den überhaupt? wenn ja gibt es dafür schon eine Methode?
EDIT:
@srea war natürlich schmarrn was Ich da geschrieben habe natürlich benutze ich die getBytes()- methode
ich meinte die die gegenoperation der getBytes()-methode
EDIT2:
vielleicht drück ich mich zu undeutlich aus!?
Bevor du aus deinem gezippten byte[] wieder einen String machen kannst, musst du es wieder entzippen. Danach sollte der Stringkonstruktor [c]String(byte[])[/c] auch wieder ein sinnvolles Ergebnis erzeugen.
EDIT: Warum überhaupt das byte[]-Gehampel? Wenn du einfach nur Strings an einen Server senden willst, dann könntest du doch auch einen ObjectOutputStream in deinem Client bzw. einen ObjectInputStream in deinem Server verwenden.
Gegenfrage, weißt du eigentlich, was beim Komprimieren prinzipiell geschieht? Wenn ja, sollte dir auch eigentlich klar sein, warum du den Datenstrom erst einmal wieder dekomprimieren musst.
Worauf du hinaus willst, ist mir aber trotzdem schleierhaft ... Wozu überhaupt die Kompression?
Ich glaube du verwechselst da immer noch was. Die Methode toString() wandelt dir dein byte-array nicht in den String um der in deinem byte-array steht. Umformen von toString() zu byte[] macht in meinen augen also wenig sinn ???:L
Evtl. ist das ja was du suchst:
Java:
String test ="TestXtring";// mache irgendwas mit den Bytes:byte[] bytes = test.getBytes();
bytes[4]=115;String neuerTestString =newString(bytes);System.out.println(neuerTestString);// (Ausgabe: Teststring)
mir ist bewusst, dass nach dem komprimieren, die Daten verwurschtelt werden
mein hauptproblem ist folgendes:
-ich habe einen sehr großen string
-dieser soll mit einem speziellem verfahren encodiert werden
-da der daraus entstandene QRCode sollte eine maximale Größe nicht überschreiten -(Anwendungsabhängig)
-ergo muss ich die zu codierenden Daten Synthaktisch verkleinern, der Informationsgehalt muss dabei erhalten beliben
- da der algorithmus nur alphanumerische Strings encoded, müsste ich doch den String so komprimieren
, dass dieser ebenso alphanumerisch ist
-einen String direkt zu zippen funktioniert mit den vorhandenen Libaries nicht
deshalb der umweg über byte[] (was ja auch völlig klar ist)
mein problem ist nicht der zippvorgang
mein problem ist einen komprimierten string im utf8 format zu erhalten
Du hast einen String. (Stimmt das? Ist das wirklich kein Byte-Array, das du da hast?)
Dieser muss komprimiert werden. (Ja?)
Das Kompressionsergebnis muss wieder in einen Container (Ja?), und dieser Container kann nur ein String sein (Ja?), und dieser String darf nur [ASCII-Zeichen? Unicode-Zeichen? Mit/ohne Steuerzeichen?] enthalten.
Dieser String muss anschließend wieder wo hin. (Ja, wohin eigentlich?)
Kannst du deinen largeString nicht in viele kleine substrings zerlegen, diese dann einzeln durch den "QR-Code-Creator" schicken und danach wieder zusammensetzen? (Weiß grad nicht wie der algo funktioniert und ob das so überhaupt möglich ist...)
Hm, ich weiß zwar nicht, wie festgenagelt diese Verarbeitung ist, aber:
Was bitte ist ein compressedString?
Was erwartet der "QR-Code-Creator"? Einen java.lang.String? Oder Bytes? Oder ASCII-Zeichen? Oder Unicode-Zeichen? Nimmt er jeden beliebigen String, oder muss dieser String einen bestimmten Aufbau haben? Gibt es eine Längenbeschränkung für den String?
Bist du dir sicher, dass der "QR-Code-Creator" richtige Ergebnisse liefern kann, wenn ein "compressedString" eingegeben wird?
Warum geschieht die Kompression/Dekompression mittendrin und nicht ganz am Ende bzw. Anfang der Verarbeitung?
um auf deine fragen zu antworten ARK:
alles richtig verstanden
die UTF8 codierung umfasst ja ASCII- sowie Unicode-zeichensatz
es soll aber nur der Ascii-zeichensatzt genommen werden (eigentlich nur Zahlen und Buchstaben)
wenn man sich das compressedByte[] wertemäßig anschaut kommen auch negative Werte Integer raus
in der UTF8-Tabelle wären das Werte am ende der Tabelle - also nicht Ascii zeichen
steuerzeichen werden von der Anwendung erkannt und ausgewertet
Und dann noch: Zeig doch mal konkrete Aufrufe von Methoden dieses "QR-Code-Creator"s. Oder besser: Zeige, wie bisher der Code aussieht, den du ändern willst.
Weißt du, warum die byte-Werte auch negativ sein können? Und wie man sie (bitgenau) gleichwertig positiv macht? Und was das überhaupt bedeutet, wenn ein byte[] einen UTF-8-Datenstrom repräsentiert?
@eikeB:
nein das wäre unnützt , so hätte man für jeden substring einen eigenen qrcode(2-d-matrixcode)
@ark:
<<<<<Was bitte ist ein compressedString?>>>>>
- compressedString habe ich jetzt einfach mal den komprimierten string genannt
<<<<<
Was erwartet der "QR-Code-Creator"? Einen java.lang.String? Oder Bytes? Oder ASCII-Zeichen? Oder Unicode-Zeichen? Nimmt er jeden beliebigen String, oder muss dieser String einen bestimmten Aufbau haben? Gibt es eine Längenbeschränkung für den String?
>>>>>
Ich fang von hinten an. Ja die Längenbeschränkung ist die folgende:
Zeichensätze Begrenzung
--------------------------------------------------
numerisch max 1156 ziffern
alphaNum max 698 zeichen
ISO (Latin und Kana) max 492 Bytes
Kanji max 270 Worte (16 Bit)
-die obergrenzen werden nie überschritten- der eigentlich qrcode kann also erstellt werden
- das gerät , welches den code erfasst hat jedoch eine begrenzte aufnahmefähigkeit
- 145 codierte zeichen sind zuviel die hälfte wäre besser
mit dem zip-algo würde ich auf ca 85 zeichen kommen
der qr-creator braucht einen JAVA.lang.String - das ist richtig
<<<<<<<<<
Bist du dir sicher, dass der "QR-Code-Creator" richtige Ergebnisse liefern kann, wenn ein "compressedString" eingegeben wird?
>>>>>>>>>
solange der compressedString: alphanumerisch ist (wie ich jetzt schon dieses Wort hasse^^)
schlägt die Encodierung nicht fehl
erlaubte zeichen: 0-9, A-Z, a-z, $*%+-./:]+
<<<<<<<<<<<
Warum geschieht die Kompression/Dekompression mittendrin und nicht ganz am Ende bzw. Anfang der Verarbeitung?
>>>>>>>>>>>
die Kompression geschieht doch am anfang!
und die dekompression am ende dieses großen zyklus
alles was du wissen musst,ist dass der string als parameter übergeben wird- den QR-creator selber stelle ich hier ganz bestimmt nicht rein, weil das nicht auf meinen mist gewachsen ist
und ja ich weiß warum die werte negativ werden - hängt ja vom zip-algo ab
und an den byte values werde ich ganz bestimmt nichts verändern
ich finde es auch nett, dass du mich mit anregenden fragen zur lösung bringen willst aber ich glaube
ich muss mir da was anderes einfallen lassen
denn so komm ich nicht weiter
Kannst du auch Gleichheitszeichen verwenden? Wenn ja: Base64 ? Wikipedia
Damit kannst du aus deinem komprimierten byte[] einen ASCII-String erstellen. Java bietet auch Klassen zum BASE64-Enkodieren und -Dekodieren, allerdings liegen diese innerhalb eines sun-packages.
Wenn du kein = nutzen kannst, ersetze es vielleicht einfach durch ein anderes, vom BASE-Algorithmus nicht benutztes Zeichen und ersetze dieses wiederum durch das =, bevor du den String dekodierst.
EDIT: Ich Dummerchen - ich habe vergessen, dass du nur wenig Platz zur Verfügung hast. BASE64 erhöht den Platzverbrauch, da wird auch das Zippen nicht mehr viel helfen. Vielleicht findest du ja einen anderen Algorithmus.
ja bei base64 war ich auch schon-
aber moment mal
der zip-algo arbeitet ja so, dass er sich wiederholende zeichen zählt und zusammenfügt
eventuell erhöht sich dann die kompressionsrate
obwohl, es werden dabei aus 3byte 4byte gemacht, wenn mir nichts anderes einfällt kann man das immer noch ausprobieren
trotzdem danke für deinen tipp!
Ja, Base64 war auch mein erster Gedanke. Dennoch ein paar Anmerkungen:
Das bytes negativ sind, liegt nicht am Kompressionsalgorithmus, sondern an der Interpretation der 8 Bits (Zweierkomplement).
Wenn das Ding auch mit Kana und Kanji (für alle anderen: Japanisch) umgehen kann, warum sollten dann nur "0-9, A-Z, a-z, $*%+-./:]+" erlaubt sein? (Oder verwechsle ich da gerade etwas?)
Wenn die Datenmenge ein Problem ist, auf dass du zu Kompressionsalgorithmen greifen musst: Dir ist bewusst, dass es zu jedem beliebigen (verlustfreien) Kompressionsalgorithmus mindestens eine Eingabe/Bitfolge gibt, die durch diesen Algorithmus nicht weiter komprimiert werden kann?
Ein besserer Kompressionsalgorithmus wäre übrigens wahrscheinlich der Huffman-Code, aber das nur am Rande; die gerade genannte Beschränkung gilt ja trotzdem.
EDIT: Die Wahrscheinlichkeit, dass sich Zeichen in "normalen" Texten unmittelbar wiederholen, ist extrem gering, bei Kanji kommt sie so gut wie nie vor. (Gerade bei Kanji würde man an der Stelle eher auf das (stimmhafte) Wiederholungszeichen stoßen.)
also das mit der zeichen beschränkung war so gemeint:
im allgemeinen kann der qrcode die auf der 1. seite dieses threads genannten zeichensätze aufnehmen
in meinen anwendungsfall wird aber nur der alphanumerische zeichensatz genutzt
(kanji und kana hab ich zu vergleichzwecken hinzugeschrieben, dies sollte verdeutlichen, dass die datenkomprimierung nicht auf den qr-code zurückzuführen ist)
an den huffman habe ich auch schon gedacht - wenn es dafür fertige libaries gibt schön und gut
wenn ich den jedoch noch selber implementieren müsste, würde das meinen zeitrahmen vollkommen sprengen
ps: keiner hat etwas von normalen texten erzählt:
es ging lediglich um die zeichen, ich habe kein wort über häufigkeit des auftretens der zeichen verloren
das leserlich habe ich auf den synthax bezogen und nicht auf die semantik - sorry wenn das so interpretiert wurde
Du kannst dir byte[] wie eine eigene Klasse vorstellen, wobei aber insbesondere die Methode toString() nicht(!) überschrieben wurde und demzufolge das macht, was in Object.toString() gemacht wird: ein String zurückgegeben, der den Namen der Klasse und den Hashwert zurückgibt, mehr nicht. Das ist also 100%ig etwas, das du nicht gebrauchen wirst.
Wegen Kompression: Das Paket java.util.zip hält einige eventuell interessante Klassen bereit.
EDIT: Dass hier kaum einer versteht, was du willst, könnte vor allem daran liegen, dass du bisher noch keinen ganz konkreten Code gezeigt hast. Du musst diesen "QR-Code-Creator" nicht posten, aber die Aufrufe wären interessant.
EDIT2: Warum heißt es an einer Stelle, Steuerzeichen wären erlaubt, und an anderer Stelle wieder, man dürfe nur dieunddie Zeichen (aber keine Steuerzeichen) eingeben?
/**
* Compress data.
* @param bytesToCompress is the byte array to compress.
* @return a compressed byte array.
* @throws java.io.IOException
*/privatestaticbyte[]Compress(byte[] bytesToCompress)throwsIOException{// Compressor with highest level of compression.Deflater compressor =newDeflater(Deflater.BEST_COMPRESSION);
compressor.setInput(bytesToCompress);// Give the compressor the data to compress.
compressor.finish();// Create an expandable byte array to hold the compressed data.// It is not necessary that the compressed data will be smaller than// the uncompressed data.ByteArrayOutputStream bos =newByteArrayOutputStream(bytesToCompress.length);// Compress the databyte[] buf =newbyte[bytesToCompress.length +100];while(!compressor.finished()){
bos.write(buf,0, compressor.deflate(buf));}
bos.close();// Get the compressed datareturn bos.toByteArray();}
unzip-Methode:
Java:
/**
* Decompress data.
* @param compressedBytes is the compressed byte array.
* @return decompressed byte array.
* @throws java.io.IOException
* @throws java.util.zip.DataFormatException
*/privatestaticbyte[]Decompress(byte[] compressedBytes)throwsIOException,DataFormatException{// Initialize decompressor.Inflater decompressor =newInflater();
decompressor.setInput(compressedBytes);// Give the decompressor the data to decompress.
decompressor.finished();// Create an expandable byte array to hold the decompressed data.// It is not necessary that the decompressed data will be larger than// the compressed data.ByteArrayOutputStream bos =newByteArrayOutputStream(compressedBytes.length);// Decompress the databyte[] buf =newbyte[compressedBytes.length +100];while(!decompressor.finished()){
bos.write(buf,0, decompressor.inflate(buf));}
bos.close();// Get the decompressed data.return bos.toByteArray();}
TestMAIN:
Java:
publicstaticvoidmain(String[] args){/*
* Charset-Standards:
*
* Charset Description
*
* US-ASCII Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set
* ISO-8859-1 ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1
* UTF-8 Eight-bit UCS Transformation Format
* UTF-16BE Sixteen-bit UCS Transformation Format, big-endian byte order
* UTF-16LE Sixteen-bit UCS Transformation Format, little-endian byte order
* UTF-16 Sixteen-bit UCS Transformation Format, byte order identified by an optional byte-order mark
*
* *///String der encodiert werden soll String str1 =newString("{\"E\":\"Acer Cooperation...........\",\"B\":\"111111111,11\",\"K\":\"0123456789\",\"BL\":\"80080080\","+"\"V\":\"eeeeeeeeeeeeegggggggggggaaaaaaaaaallll................\"}");//******************************************************************************************************************************//==============================================================================================================================//******************************************************************************************************************************//ZipVariante 1byte[] byte2compress = str1.getBytes(Charset.forName("UTF8"));byte[] compressedBytes = NULL;//AusgangssituationSystem.out.println("Ausgangssituation:\n=============================================================");System.out.println("string:\n"+ str1);System.out.println("string.lenght: "+ str1.length());System.out.println("\nbyte[]: "+ byte2compress);System.out.println("byte[].lenght: "+ byte2compress.length);System.out.println("byte[].toString: "+ byte2compress.toString());for(int i=0;i < byte2compress.length;i++){System.out.print(" "+ byte2compress[i]);}//zippentry{
compressedBytes =Compress(byte2compress);}catch(IOException e){e.printStackTrace();}System.out.println("\n\nNach Komprimierung Variante 1:\n=============================================================");//System.out.println("string:\n" + new String(compressedBytes,Charset.forName("UTF8")));System.out.println("string:"+newString(compressedBytes.toString()));System.out.println("string.length: "+String.valueOf(compressedBytes.length));System.out.println("\nbyte[]: "+ compressedBytes);System.out.println("byte[].lenght: "+ compressedBytes.length);System.out.println("byte[].toString: "+ compressedBytes.toString());for(int i=0;i < compressedBytes.length;i++){System.out.print(" "+ compressedBytes[i]);}//_________________________________________________________________________________________//byte to stringString string2transmit = compressedBytes.toString();//----------------------------------BEIM-SERVER--------------------------------------------byte[] decompressedBytes = NULL;/*
byte[] receivedBytes = NULL;
//set received Bytes from transmitted String
//~> "byte[] receivedBytes= string2transmit.toByte[]"
char[] helpingCharArray= string2transmit.toCharArray();
receivedBytes = new byte[helpingCharArray.length];
for(int j=0; j < helpingCharArray.length; j++)
{
receivedBytes[j]=(byte) helpingCharArray[j];
}
*///unzippentry{
decompressedBytes =Decompress(/*receivedBytes*/compressedBytes);//decompressedBytes = Decompress((byte[])compressedBytes.toString()); }catch(IOException e){e.printStackTrace();}catch(DataFormatException e){e.printStackTrace();}String str2 =newString(decompressedBytes);System.out.println("\n\nDekomprimierung Variante 1:\n=============================================================");System.out.println("string:\n"+ str2);System.out.println("\nbyte[]: "+ str2.getBytes(Charset.forName("ISO-8859-1")));System.out.println("stringLenght: "+ str2.length());}
erstmal danke für deine Idee
ich probiers gleich mal aus
Edit:
Schade hat nicht geklappt
aber einen Versuch war es wert
der komprimierte String besitzt an vielen Stellen immer noch Zeichen, die nicht vom QR-Algorithmus erfasst werden
Tja, dann wird's kompliziert: Welche Zeichen werden denn angenommen? Du hast zwar schon mal das angedeutet, aber ich bin mir nicht sicher, ob ich das richtig gelesen habe. Gib doch deswegen mal alle zur Verfügung stehenden Zeichen einzeln an. Wenn du das gemacht hast, muss man dann die Anzahl dieser Zeichen zählen.
Je nachdem, was dann da für eine Zahl rauskommt, kannst/musst du dich zwischen Geschwindigkeit und Speicherplatzverbrauch entscheiden. Hinweis: Je mehr Zeichen du findest, desto besser steht es um den Speicherverbrauch.
also wir haben im worstCäse: 115
Zeichenvorrat: [a-z $*%+-./:] und [0-9]+
(die eckigen Klammern zählen nicht dazu und das + hinter [0-9] bedeutet auch mehrmals möglich )
Steuerzeichen werden ebenso encodiert
ein QRCode mit 115 Zeichen ist schon eher einer von der großen Sorte
die Hälfte wäre angenehmer so um die ~ 50 Zeichen
das Zip-verfahren aus dem "java.lang.zip" Package ist eher ungeeignet, da logischer Weise der Zeichenvorratsbereich des komprimierten Strings überschritten wird
(bzw. zum interpretieren der bytes nicht ausreicht)
was gibt es denn noch für Komprimierungsverfahren?
kennt jemand noch welche, die für Texte geeignet sind?
ich suche der Zeit,ob schon einige dieser Verfahren implementiert sind und in diversen Libaries vorliegen
Vielleicht kennt ihr schon welche?
Edit:
ich würde mehr Wert auf geringen Speicherverbrauch legen!
Zeichenvorrat: [a-z $*%+-./:] und [0-9]+
(die eckigen Klammern zählen nicht dazu und das + hinter [0-9] bedeuted auch mehrmals möglich )
Steuerzeichen werden ebenso encodiert
Was denn nun, willst du viel übertragen können oder nicht? Wie schon oben erwähnt, gibt es eine Grenze (maximale Entropie), man kann nicht beliebig stark komprimieren. Es ist überhaupt schon verwunderlich, dass überhaupt Datenmengen erzeugt werden, die in so ein Ding rein sollen, das gar nicht für diese Datenmengen ausgelegt ist.
das zip verfahren aus dem java.lang.zip package ist eher ungeeignet da logischer weise der zeichenvorratsbereich des komprimierten strings überschritten wird (bzw. zum interpretieren der bytes nicht ausreicht)
Vorsicht: Komprimiert und dekomprimiert werden Bytes, keine Zeichen! Es gibt zwar eine Zuordnung zwischen Bytes und Zeichen, nämlich den Zeichensatz, aber dir sollte bewusst sein, dass das alles völlig verschiedene Dinge sind.
kenn jemand noch welche, die für Texte geeignet sind?
ich suche der zeit ob schon einige dieser verfahren implementiert sind und in diversen Libaries vorliegen
Vielleicht kennt ihr schon welche?
Der Deflate-Algorithmus, der in java.util.zip zum Einsatz kommt, benutzt bereits Huffman und andere. Besser sind vielleicht noch die arithmetische Kodierung bzw. 7z/LZMA. (Lizenzsachen mal außer Acht gelassen, sofern es da irgendwie Probleme geben könnte; weiß ich gerade nicht.) Was machst du denn, wenn du trotz Komprimierung zu viele Daten erzeugst?
Mein Vorschlag: Rechne mal nach, ob du das 4/3-fache an Daten (nach der Komprimierung) vertragen kannst. Wenn ja, reicht Base64 aus (vorausgesetzt, wir kriegen irgendwie 64 bis 65 Zeichen im Zeichenvorrat zusammen).
1. richtig so war es gemeint, maximal kann der unstrukturierte string 115 zeichen lang sein
dazu: schöner wär ein JSON-string der bräuchte dann 147 Zeichen maximal
2. der string ist quasi aus dem Zeichenvorrat zusammengesetzt, also ja zahlen und buchstaben sind vereinbar
3. leerzeichen war mit in der menge enthalten (zwischen "z" und "$")
4. großbuchstaben sind eher ungünstig, da dadurch der code aufgebläht wird
dazu: die eingabe wird so realisiert, das wirklich nur solche zeichen (wie im vorrat) angenommen werden
wird also der string komprimiert sollten auch nur zeichen aus diesem vorrat enthalten sein
5. unter steuerzeichen meine ich dann sowas wie: \n \t \" (mehr wird eigentlich nicht gebraucht, meine ich)
6. nein, die datenmengen passen allemal in den QRCode, die spezielle anwendung erfordert nur weniger
dazu: der qrcode wird ja an einer stelle eingelesen , d.h. aufgenommen und decodiert
performanter weise sollte der code nicht unnötig groß sein, deswegen die beschränkung auf "50 zeichen" anstelle von "115 zeichen"
der code wird mühelos generiert , nur lassen sich solche "datenmengen" nur schlecht vom otto-normalen- standard-gerät schlecht einlesen
fakt ist: ich möchte einen string auf die hälfte schrumpfen lassen, aus performancegründen
7. ja mir ist bewusst, dass byte[] komprimiert werden, wie soll es denn sonst funktionieren
8. ok 7z/LZMA hab ich dann auch noch endeckt, aber wird nur das gleiche in grün sein
9.base64 haben wir doch schon ausgeschlossen!
ich weiß jetzt auch nicht warum du (ich dutze dich jetzt einfach mal) aufeinmal den string wieder größer machen willst
- möchtest du mich ärgern^^
nochmal mein Hauptziel:
mache GROß-String zu kleinString
1. richtig so war es gemeint, maximal kann der unstrukturierte string 115 zeichen lang sein
dazu: schöner wär ein JSON-string der bräuchte dann 147 Zeichen maximal
Verstehe ich das richtig: Der Zeichenvorrat ist durch die Spezifikation für Zeichenketten in JSON beschränkt? Und weiter: Das, was benötigt wird, ist eine in JSON gültige Zeichenkette? Muss die 115-Zeichen-Begrenzung eingehalten, bevor in gültige JSON-Zeichenketten kodiert wird, oder dürfen es nicht mehr als 115 Zeichen sein, nachdem in JSON kodiert wurde?
Die Frage stelle ich, weil davon abhängt, welche Zeichen nun wie kodiert werden müssen und welche Zeichen sich eignen (und welche nicht).
Gibt es eigentlich noch mehr Beschränkungen/Kodierungen/Abhängigkeiten/etc., von denen hier noch nichts gesagt wurde?
4. großbuchstaben sind eher ungünstig, da dadurch der code aufgebläht wird
dazu: die eingabe wird so realisiert, das wirklich nur solche zeichen (wie im vorrat) angenommen werden
wird also der string komprimiert sollten auch nur zeichen aus diesem vorrat enthalten sein
Was heißt das denn jetzt wieder, dass durch Großbuchstaben Code aufgebläht wird? Warum? Und was für ein Code überhaupt?
Eine dringende Bitte: Stell die gesamte "Verarbeitungspipeline" dar: Was für Daten stehen am Anfang und wie sind sie kodiert? In welche Maschine gehen diese Daten? Was macht die Maschine mit den Daten? Wie ist die Ausgabe dieser Maschine kodiert? Wohin gehen dann die so kodierten Daten als nächstes (welche Maschine)? Was macht diese Maschine mit den Daten? usw. usf. Wichtig ist dabei vor allem, dass du jeweils die Kodierung der Daten angibst. Langsam blicke ich nämlich nicht mehr durch, welche Daten jetzt wie kodiert woher kommen und wohin gehen.
6. nein, die datenmengen passen allemal in den QRCode, die spezielle anwendung erfordert nur weniger
dazu: der qrcode wird ja an einer stelle eingelesen , d.h. aufgenommen und decodiert
performanter weise sollte der code nicht unnötig groß sein, deswegen die beschränkung auf "50 zeichen" anstelle von "115 zeichen"
der code wird mühelos generiert , nur lassen sich solche "datenmengen" nur schlecht vom otto-normalen- standard-gerät schlecht einlesen
fakt ist: ich möchte einen string auf die hälfte schrumpfen lassen, aus performancegründen
9.base64 haben wir doch schon ausgeschlossen!
ich weiß jetzt auch nicht warum du (ich dutze dich jetzt einfach mal) aufeinmal den string wieder größer machen willst
- möchtest du mich ärgern^^
nochmal mein Hauptziel:
mache GROß-String zu kleinString
Ich will dich nicht ärgern, falls du das wissen wolltest. Es ist nur einfach so, dass du einen Verlust in der Informationsdichte hinnehmen musst, wenn du nicht alle möglichen Bitkombinationen zulassen kannst (sprich, wenn dein Zeichenvorrat für Zeichen pro Byte kleiner ist als 256).
ich hab so das Gefühl, als wenn wir ständig aneinander vorbeireden.
Dabei meine ich es gar nicht so kompliziert, wie es wohl rüberkommt .
Das komplette Flussdiagramm kann ich nicht reinstellen, da dies kein opensource Projekt ist.
Genaue Angaben kann ich nicht geben.
Ich wollte lediglich nur wissen, ob es möglich wäre einen 115 Zeichen langen String zu einem ca. halb so großen String zu komprimieren, wobei die Elemente dieser beiden Strings aus ein und dem selben Zeichenvorrat sind.
pass auf jetzt, ganz logisch nochmal von Anfang erklärt:
Ausgangssituation:
ich habe einen strukturierten String (egal ob JSON,XML oder "Marke Eigenbau" das ist zunächst egal)
Nehmen wir jetzt einmal wir hätten einen strukturierten String "Marke Eigenbau", der wie Folgt aussieht:
das sind genau 115 Zeichen
länger kann der String nicht werden (das ist so festgelegt!)
dann wird ein QRCode (dies ist ein spezieller 2D-Matrixcode, auf den ich hier nicht weiter eingehe)
aus diesem String erzeugt
je größer der String desto größer der QRCode
um den QRCode kleiner zu machen, muss auch ein kleinerer String encodiert werden
Das ist mein Ziel ich möchte einen kleineren QRCode, der die gleichen Daten beinhaltet wie der größere.
Der QRCodealgorithmus arbeitet nur mit Strings mit unseren schon oft genannten Zeichvorrat:
Code:
abcdefghijklmnopqrstuvwxyz $*%+-./:0123456789
Die Größe des QRCodes ist abhängig von der Art der Zeichen.
Es passen mehr Ziffern in einen QRCode als Kleinbuchstaben.
Es passen mehr Kleinbuchstaben als Großbuchstaben in einen QRCode.
Nochmal anders gesagt. Der QRCode mit "AA" als Inhalt ist größer als der QRCode mit "aa".
Deshalb wird der Anfangsstring nur in Kleinbuchstaben aufgenommen!
In diesem String fallen keine Steuerzeichen an! (wird jetzt so festgelegt).
Bis jetzt war von einer Komprimierung noch nicht die Rede.
Mein QRCode soll jetzt kleiner werden, ergo mache die DatenString kleiner ohne Informationen zu verlieren.
Geht soetwas denn überhaupt unter der Vorraussetzung, dass die komprimierte String den sleben Zeichvorrat von
Code:
abcdefghijklmnopqrstuvwxyz $*%+-./:0123456789
hat?
Denn dieser komprimierte String soll nun QREncoded werden.
das sind genau 115 Zeichen
länger kann der String nicht werden (das ist so festgelegt!)
dann wird ein QRCode (dies ist ein spezieller 2D-Matrixcode, auf den ich hier nicht weiter eingehe)
aus diesem String erzeugt
[…] ich möchte einen kleineren QRCode, der die gleichen Daten beinhaltet wie der größere.
Der QRCodealgorithmus arbeitet nur mit Strings mit unseren schon oft genannten Zeichvorrat:
Code:
abcdefghijklmnopqrstuvwxyz $*%+-./:0123456789
[...] Der QRCode mit "AA" als Inhalt ist größer als der QRCode mit "aa".
Deshalb wird der Anfangsstring nur in Kleinbuchstaben aufgenommen!
Bis gerade eben dachte ich: "Jetzt wird's endlich klarer!", aber dann … das verstehe ich wieder nicht! Großbuchstaben erzeugen schneller größere QRCodes als Kleinbuchstaben. Aber hieß es nicht gerade die ganze Zeit, Großbuchstaben wären ausgeschlossen? Und um welche Länge geht es dir eigentlich: Um die Länge der Eingabe oder um die Länge der QRCodes?
Der String, den du da oben als Beispieleingabe zeigst, kann nicht aus dem Zeichenvorrat, den du darunter nennst, entstanden sein: Dem Zeichenvorrat fehlt ';'. Was stimmt denn nun? Ist das Beispiel eine gültige Eingabe oder stimmt der Zeichenvorrat?
Da gibt's bei mir wieder Fragezeichen! Was soll denn nun kleiner werden, die Eingabe für das QR-Ding oder die Ausgabe des QR-Dings?
Für mich stellt sich das gerade so dar:
Du möchtest (aus mir nicht nachvollziehbaren Gründen) einen String komprimieren. Dieser String entspringt dem oben genannten Zeichenvorrat. Nach der Kompression soll ein String rauskommen, der nur aus Zeichen desselben Zeichenvorrats besteht und die gleichen Informationen aufgenommen hat, aber dafür weniger Zeichen benötigt.
Dir ist dazu ferner bewusst, dass dann die ursprüngliche Kodierung des Strings futsch ist und die Komprimierung nicht immer glücken kann (es also mindestens eine Zeichenkette gibt, die 115 Zeichen lang ist und nicht komprimiert werden kann).
Natürlich geht das. Das macht Deflate ja auch so: Dort ist die Eingabe jedes Byte [0x00 ; 0xFF] zugelassen, und rauskommen kann auch jedes Byte [0x00 ; 0xFF]. In deinem Fall ist es ähnlich, nur das halt nicht 256 Zeichen zur Verfügung stehen, sondern nur 45, weshalb ja nun die Anzahl der Symbole der Deflate-Ausgabe von 256 auf 45 reduziert werden muss. Dies geht aber nur, wenn dafür die Länge des Strings wieder zunimmt. Deswegen muss die Ausgabe von Deflate (die komprimierte Version also) jetzt länger werden, und zwar mindestens mit dem Faktor log(256) / log(45) = 1,4567.
kurzer hinweis zu den unklarheiten noch:
die Länge des Strings beeinflusst die Länge des QRCodes.
schraubt man an dem string so ändert man auch den qrcode (das habe ich aber schon geschrieben!)
wenn es mein ziel ist den qrcode zu reduzieren dann ist es mein unterziel auch den string zu reduzieren
(siehst du jetzt die relation zwischen STRING und QRCODE?)
aber jetzt weiß ich erstmal wo unser kommunikationsproblem steckt:
der oben genannte zeichenvorrat bezog sich auf den tatsächlichen Datenstring
der QRCode arbeitet mit dem US-ASCII (das war mein fehler)
demzufolge haben wir zum erfolgreichen QRcodieren die ASCII-Zeichen von 33 bis 127
-> tut mir leid das ist mir ebengrade aufgefallen -> meine schlampigkeit
also neu :
________
-eingangsstring (US-ASCII ohne Steuerzeichen) zu komprimierten String (US-ASCII ohne Steuerzeichen)
-was tatsächlich in den eingangsString eingegeben wird ist eine Teilmenge von "US-ASCII ohne Steuerzeichen"
-tatsächlich stehen im eingangsstring zu beginn elemente der folgenden Menge drin:
[a-z +$*-/,%]
zum thema großbuchstaben: großbuchstaben könnten in einen QRCode encodiert werden, dies tritt aber hier nicht auf (wir einigen uns darauf, dass nur kleinbuchstaben eingegeben werden- zumindest zu beginn- was dann im komprimierten string steht darf auch groß geschrieben sein)
also wenn ich das richtig verstanden habe:
ich müsste, wenn ich den deflate algo verwenden wollen würde, also nur die zeichen von
[0x21 bis 0x7F] zulassen (ascii 33 bis ascii 127)
-> zu Beginn liegen alle Zeichen im US-ASCII-Bereich
-> nach der Komprimierung befinden sich negative werte im byte[] -> diese negativen Werte zu 255 "ergänzen" (also abziehen)
-> jetzt muss ich den QRCodecreator nur noch dazu bringen die erweiterten ASCII-Zeichen zu encoden
und dann klappt das doch oder was meint ihr?
Wir haben also 95 Zeichen zur Verfügung, damit können wir locker Base64 verwenden. Cooler wäre natürlich, wenn wir Steuerzeichen auch verwenden könnten:
128 Zeichen --> Faktor 1,142857~ (leicht zu berechnen)
95 Zeichen --> Faktor 1,217683... (schwer zu berechnen)
64 Zeichen (Base64) --> Faktor 1,3~ (leicht zu berechnen)
Meine Empfehlung: Base64 (wie schon des öfteren gesagt wurde): Ist standardisiert, leicht zu implementieren und sehr schnell und speicherschonend.
Bei 128 Zeichen muss die Länge extra gespeichert werden, wenn sie nicht ohnehin bekannt ist, weil es schwer wird, dort ein Padding durchzuführen. Ansonsten ist auch das leicht implementiert und sehr performant. 95 Zeichen haben zwar den Vorteil gegenüber Base64, eine minimal bessere Kompression zu ermöglichen, machen die Sache jedoch unverhältnismäßig kompliziert.
The choice is up to you.
Ark
EDIT: Hm, jetzt kann also auf einmal das Ding doch (möglicherweise) mit 0x00 bis 0xFF (256 Zeichen) umgehen ...
Also, wenn es doch möglich ist, sei noch Folgendes gesagt:
Die Umrechnung von negativen Zweierkomplement-Zahlen in den bitgleichen positiven Bereich ist einfach [c]int wert = wertAlsByte & 0xFF;[/c].
Du solltest dir Gedanken um den Zeichensatz machen, eventuell spielt der nämlich eine Rolle. (Bei nur ASCII sollte es keine Probleme geben.)
aber wenn ich base64 verwende dann wird doch der string größer. oder nicht?
z.B. aus "hallo" wird "aGFsbG8="
das ist doch schlecht
oder wo meinst muss base 64 eingesetzt werden nach oder vor dem komprimieren?
Kompression soll ja den string kürzen!
EDIT:
VERDAMMT! Da ist ja ne lücke zwischen US-ASCII und erweiterter ASCII -
das Steuerzeichen "DEL" auf asciiwert "127" soll auch ignoriert werden - kann ja nicht als char in den string eingefügt werden und somit auch nicht encodiert werden
Ja, es ist schlecht in Hinblick auf die Länge des Strings, aber notwendig, wenn du weniger als 256 Symbole zur Verfügung hast.
In 40 Bits, also 5 Bytes an Daten gehen allerhöchstens 40 Bits an Information rein. Ein Byte ist 8 Bit groß und bietet 2^8 = 256 Symbole. Diese 256 Symbole können aus dem Deflater rauskommen. Nun hast du aber nur noch (bspw.) 64 Symbole zur Auswahl, weil mehr Symbole nicht weiterverarbeitet werden können. Also muss man die Information, die in 8 Bit steht, irgendwie so umkodieren, dass es nur noch x*6 Bit werden, weil log(64)/log(2) = 6 ist, die 64 Symbole also 6 Bit zur Kodierung brauchen. Und dann kommt man leicht darauf, dass x genau 4/3 = 1,333~ ist. Die neue Zeichenkette ist also 1,333mal so lang wie der komprimierte Datenstrom. Aus den ursprünglichen 40 Bit (5 Bytes) werden so 53,3 --> 54 Bit oder 6,75 --> 7 Bytes, wobei von diesen 7 Bytes immer nur 3/4 benutzt werden, das letzte Viertel bleibt ungenutzt.
Oder wie denkst du dir, sollen die Informationen untergebracht werden?
Wie oben gesagt: Die Kompression kürzt ihn, erzeugt aber in der Ausgabe mehr Symbole, als weiterverarbeitet werden können. Deswegen muss die Anzahl der Symbole auf Kosten der Länge reduziert werden.
EDIT:
VERDAMMT! Da ist ja ne lücke zwischen US-ASCII und erweiterter ASCII -
das Steuerzeichen "DEL" auf asciiwert "127" soll auch ignoriert werden - kann ja nicht als char in den string eingefügt werden und somit auch nicht encodiert werden
Hm, entweder es liegt daran, dass ich wirklich keine Ahnung habe, oder es liegt an der Weiterverarbeitung. Jedenfalls höre ich hier gerade zum ersten Mal, dass man 0x7F nicht in einem char und nicht in einem String speichern könnte.
EDIT: Du solltest dir vllt die anderen Konstruktoren von Deflater und Inflater angucken und [c]nowrap = true[/c] setzen, vielleicht spart das noch etwas Speicher (wenn ich die Dokumentation jetzt richtig verstanden habe).
mein problem sind jetzt die steuerzeichen!
wie kann man in einem string signalisieren, dass dort an einer bestimmten stelle ein steuerzeichen auftritt- und zwar möglichst mit EINEM zeichen
mit zwei charaktern wär es ja kein problem:
z.B. ASCII =28 HEX=0x1C das entspräche FS mit einen möglichen Ausdruck: ^\
@ark
ich schau mir mal die Konstruktoren bzgl "nowrap" genauer an auf jeden fall danke für den tipp
Base64 werde ich denk ich nicht verwenden, da mein oberstes ziel dann zerstört werden würde
EDIT:
DANKE für den Tipp mit dem "nowrap"-wert
dadurch hab ich eine verkürzung des strings von 115 auf 57 das sind 6 zeichen weniger!!!
wenn wir jetzt noch das problem mit den steuerzeichen eleminieren könnten wäre das schon ein fortschritt
Ja, aber die sind doch auch alle nur 1 Zeichen bzw. (über ASCII) nur 1 Byte groß. ???:L Oder muss um den String noch eine Art Hülle, weil dieser z.B. in einem Quelltext noch verwendet wird und dieser Quelltext nicht größer als eine bestimmte Anzahl von Zeichen sein darf?
Hm...
Also ich verstehe es immer noch nicht ganz, aber wenn ich einen Rat geben darf: Komprimiere den String wie gehabt und wende anschließend Base64 auf die komprimierte Version an. Warum willst du denn den String so fanatisch verkleinern, obwohl es vielleicht gar nicht nötig und prinzipiell sowieso nicht immer möglich ist?