Nicht darstellbare Zeichen entfernen (UTF-8)

Fabio Hellmann

Erfahrenes Mitglied
Hallo Community,

ich stehe momentan vor foglendem Problem. Ich muss aus einem String (eingescannte Dokumente mit ~200 Seiten) alle nicht darstellbaren Zeichen entfernen.
Mein Ansatz war es nun, über den String bzw. jedes Zeichen zu iterieren und auf ein nicht darstellbares Zeichen prüfen. Da das aber bei einem String, der aus einem ~200 Seiten Dokument entstanden ist, sehr schlechte Performance erziehlen dürfte ist wohl klar.
Deshalb bin ich noch weiterhin auf der Suche nach einem vernünftigen Ansatz für dieses Problem. Vielleicht hat jemand von euch das gleiche schon mal gemacht oder hat einen Denkanstoß für mich. Würde mich freuen.

Gruß

Fabio
 
Hi,

lies die Datei nicht komplett in den Arbeitsspeicher, sondern in Häppchen.
Iteriere durch den Block und kopiere alle lesbaren Zeichen in einen StringBuilder, alle nicht darstellbaren Zeichen werden somit entfernt.
Schreibe den Inhalt des StringBuilders in eine andere Datei. Somit dürfte sich der Arbeitsspeicherbedarf verringern und die Performance steigen.

Das wäre mein Ansatz :)

Gruß
BK
 
Hi Bratkartoffel,

gut das du mir das mit dem Arbeitsspeicher gesagt hast, da hät ich selber fast nicht mehr dran gedacht. :)
Das Problem dabei ist nur, dass ich den Dokumenteninhalt in einer Mail verschicken will (sowohl als Attachment als auch als Text). Und den Text setze ich so:
Java:
MimeBodyPart contentBody = new MimeBodyPart();
contentBody.setText(content);
Soweit ich weiß gibt es da auch keine andere Möglichkeit, den Text einer E-Mail in "Häppchen" zu setzen. Aber wenn du da mehr weißt als ich, dann würde es mich freuen wieder etwas neues zu lernen.

Iteriere durch den Block und kopiere alle lesbaren Zeichen in einen StringBuilder, alle nicht darstellbaren Zeichen werden somit entfernt.
Das klingt super! Genau so würde ich es auch machen. Die Frage ist nur, wie erkenne ich, ob es ein darstellbares Zeichen ist oder nicht? Und wie erkenne ich das, ohne dass ich über jedes Zeichen einzeln iterieren muss?

Gruß

Fabio
 
Zuletzt bearbeitet:
Die Frage ist nur, wie erkenne ich, ob es ein lesbares Zeichen ist oder nicht?
Du meinst wahrscheinlich darstellbare Zeichen oder?
Die Erkennung dürfte sich ziemlich schwer gestalten, weil die Darstellbarkeit von Zeichen von folgenden Parametern abhängt:
• verwendeter Zeichensatz (Ok, du hast es auf UTF-8 eingegrenzt, aber auch da gibt es mehrere Möglichkeiten bei der Zusammensetzung von Zeichen, die größer als ein Byte sind)
• auf dem Zielsystem installierte Schriftarten
• verwendete Schrift (Webdings, Wingdings nutzen völlig andere Zeichen)
• verwendetes Alphabet (z.B. kyrillische, arabische, lateinische, koreanische, ... Schriftzeichen)
• Sprachspezifische Zeichen (z.B. mit Akzenten)
• erlaubte Sonderzeichen (z.B. Anführungszeichen „ “ ” " ' ’ ‘ ‚ ; schmale, geschützte und schmale geschützte Leerzeichen, die verschiedenen Geviertstriche ( https://de.wikipedia.org/wiki/- ), Gedankenstrich, Minus, Plus, das Zeichen für 3 Punkte: …; …)
• zusammengesetzte Schriftzeichen (z.B. aus lateinischen Buchstaben und Akzent/Tilde/... wobei beide in separaten Chars gespeichert werden)
Und wie erkenne ich das, ohne dass ich über jedes Zeichen einzeln iterieren muss?
Selbst wenn du nur ein paar einfache Zeichen (Groß- und Kleinbuchstaben des lateinischen Alphabets, evtl. Umlaute, Satzzeichen und Leerzeichen) zulässt, wird dir nichts anderes übrig bleiben, als über jedes einzelne Zeichen zu iterieren. Es gibt keine einfachere Möglichkeit.
Performancetipps:
• Ausführung parallelisieren (hoher Aufwand, Erfolg hängt von der verwendeten Hardware ab)
• Nur wenn du mit einer Whitelist arbeitest: Buchstaben nach absteigender Häufigkeit sortieren, d.h. häufige Buchstaben wie 's' oder 'e' sollten zuerst überprüft werden.

Prinzipiell würde ich dir davon abraten, so etwas umzusetzen (wenn es nicht unbedingt sein muss)
 
Danke ersteinmal für die ausführliche Antwort genodeftest.

Ich bin gerade eben noch über die Methode trim() von String gestoßen. Und so wie es scheint macht diese Methode genau das, was ich haben will. Ob es wirklich zu 100% stimmt, kann ich (noch) nicht genau sagen.

Gruß

Fabio
 
Ich würde an deiner Stelle replace-Methoden verwenden, welche mit regex arbeiten. So gibt es bei regex z.B. die vordefinierte Zeichenklasse:
\w - wordcharacter - ein Buchstabe, eine Ziffer oder der Unterstrich, also [a-zA-Z_0-9] (und evtl. weitere Buchstaben, z. B. Umlaute)
Negieren und fertig.
 
Hi HonniCilest,
das habe ich auch schon ausprobiert. Das Ergebnis war aber nicht befriedigend, da ich nicht weiß, welche Zeichen ein Dokument enthält und welche nicht. Daher find ich die momentane Lösung mit "string.trim()" immer noch am Besten.
Aber drotzdem danke für deinen Vorschlag. :)

Gruß

Fabio
 
Ja das dachte ich bisher auch immer. Steht schließlich auch so in der API. Allerdings bin ich in den apache commons lang in der Klasse StringUtils bei der Methode StringUtils.trim(String) ein wenig stutzig geworden, da da folgendes steht:
trim

public static String trim(String str)

Removes control characters (char <= 32) from both ends of this String, handling null by returning null.

The String is trimmed using String.trim(). Trim removes start and end characters <= 32. To strip whitespace use strip(String).

To trim your choice of characters, use the strip(String, String) methods.

StringUtils.trim(null) = null
StringUtils.trim("") = ""
StringUtils.trim(" ") = ""
StringUtils.trim("abc") = "abc"
StringUtils.trim(" abc ") = "abc"


Parameters:
str - the String to be trimmed, may be null
Returns:
the trimmed string, null if null String input
Und wenn man mal in den Code von dieser Methode reinschaut, dann steht da nur folgendes drin:
Java:
public static String trim(String str) {
    return str == null ? null : str.trim();
}
D.h. String.trim() schneidet nicht nur die Leerzeichen weg. Und da in diesem Bereich von "char <= 32" die meisten (nicht alle) nicht darstellbaren Zeichen enthalten sind, funktioniert das.

So würde ich es mir zumindest erklären. Kann auch sein, dass ich falsch liege. Wenn ja, würde ich mich über eine Aufklärung freuen. ;)

Gruß

Fabio
 
Zurück