Ignorieren von Anführungsstrichen

Hallo :wink:

Ich lese aus einer Datei folgende Zeile

„hello“, „world“, " „cool“ "

Als ausgabe möchte ich
hello
world
„cool“

mit dem String split(",") habe ich bereits das.
„hello“
„world“
„„cool““
So nun sollen die Anführungsstriche weg, sollten aber Anführungsstriche in den anderen Anführungsstriche drinne sein, dann sollen die inneren bleiben. Wie setzte ich das um?

lg
Zicky

Je nachdem, wie komplex das werden kann (gibt es etwa maskierte Anführungszeichen?), ziemlich komplex, vergleiche das Einlesen von csv-Dateien. Wenn es wirklich so einfach bleibt wie in deinem Beispiel, reicht ja ein

text = text.substring(1, text.length()-1);

Wenn du sichergehen willst, dass der eingelesene Text auch mit " beginnt und ebenso endet, kannst du das noch abfragen:

    if (text.startsWith("\"") && text.endsWith("\"")) {
        text = text.substring(1, text.length()-1);
    }

Hallo

Danke das hat mir schon geholfen, und wie du erkannt hast geht esum CSV Dateien.

Das komplexeste was hier haben ist folgendes

   "aaa","b ZEILENUMBRUCH
   bb","ccc" LEERZZEILENUMBRUCH
   zzz,yyy,xxx

Das Programm muss erkennen das in der ersten Zeile , “b zu den bb” in der nächsten zeile gehört. So das die Ausgabe
“aaa”,“bbb”,“ccc”
zzz,yyy,xxx

Sein muss, ich lese meine Datei aber Zeilenweise, wie erkenne ich also um eine Zeile geteilt wurde in zwei ode rnicht?

"\"hello\"".replaceAll("\"(.*)\"", "\\1"); (Evtl. $1 anstatt \1, bin mir gerade nicht ganz sicher)

@HoaX : Ich würde keinen regulären Ausdruck nutzen für etwas, dass sich mit einfacheren Methoden abprüfen lässt. Vor allem, wenn die Lösung schon dastand :wink:
@ZickZack :

Dann waren vermutlich beim Schreiben der Daten Zeilenumbrüche in den Daten. Das ist beim Einlesen eklig. Hast du Einfluss auf die Seite, die die Daten erzeugt? Oder musst du nun damit leben, wie es ist?

ICh muss damit leben wie es ist. Zugriff auf die csv habe ich nicht im form von sie ändern.

    "\"hello\"".replaceAll("\"(.*)\"", "\\1");

Das verstehe ich nicht ganz.

es ist ein RegEx der das gewünschte macht (verändert aber nicht den String sondern liefert neuen zurück, auf Rückgabewert achten)
ohne RegEx zu kennen brauchst du nicht weiter drüber nachdenken,


wenn es so fies läuft ist es auch nicht mehr weit bis zu einem Komma mitten im Text, durch Anführungszeichen für höhere Logik gerettet,

  • evtl. weitere innere Anführungszeichen, was Interpretation teils unmöglich machen könnte (*), auch für Excel, vielleicht nicht realistisch

weitaus aufwendiger als bisher, aber der sicherste allgemeine Ansatz ist dann, zeichenweise zu parsen:
große Schleife über alle Zeichen einzeln, nach und nach durch weitere eingelesene Zeilen gefüttert,
Status der Verarbeitung, angefangenes gelesenen Wert, fertige Werte bisher in der Zeile usw. in Variablen merken

am Anfang Ruhestatus zwischen Zeilen sowie zwischen Einträgen,
Zeichen Normalo → aktuellen Wert anfangen bzw. ergänzen
Zeichen Anführungszeichen
→ wenn am Anfang, dann speziell merken dass aktueller Eintrag in Anführungszeichen steht, ein boolean, ein Status,
Zeichen wahrscheinlich nicht zu merken, willst du ja löschen
→ wenn bei laufenden Wert, dann vielleicht beliebiger innerer Inhalt, könnte aber auch Ende sein, Info jedenfalls abbilden,
je nachdem danach auf Komma unterschiedlich reagieren, was teils unmöglich werden könnte (*)

Zeichen Komma, Zeilenumbruch → wenn aktueller Wert nicht in Anführungszeichen, dann gewiss Ende des Wertes, sonst komplizierter
usw., nach und nach Regeln aufstellen, meist abhängig von verschiedenen aktuellen Stati, testen

(*)
„aaa“,„bbb“,„ccc“
könnte die drei Werte aaa + bbb + ccc darstellen
oder auch nur zwei Werte: aaa","bbb sowie ccc

da sind die Regeln hoffentlich irgendwie klar, bisher habe ja auch nur ich , eingebracht :wink:
mit Zusatzinfos wie ‚gleicher Spaltenanzahl je Zeile‘ könnte man noch etwas retten, aber schwierig

Wenn du das zu Übungszwecken machst - in Ordnung. Aber CSV-Dateien sind trickreicher, als man gemeinhin denkt (wie man am Quote-Beispiel schon sieht). Wenn du etwas „ernsthaftes“ programmieren willst, würde ich deshalb zu OpenCSV raten, da musst du dir deswegen keinen Kopf machen.

“^.?([^"]+).$”
.group(1);
RegEx findet den ersten “inneren” Bereich, in dem keine " sind, und wovor und wonach beliebig viele " stehen. ^ ode $ optional.
Mittige oder hintere können damit nicht gefunden werden. Grüße.

Edit: ```import java.util.regex.*;

public class HelloWorld{

 public static void main(String []args){
     Pattern p = Pattern.compile("^.*?([^\"]+).*$");
     Matcher m = p.matcher("\"\"\"test\"\"\"\"");
     if (m.find())
        System.out.println(m.group(1));
 }

}```

stimmt sogar, was “ich” mir ausgedacht hab. Ohne ? nimmt er zu viel. Mit .?$ oder .+$ streikt er. Getestet auf einer Java-Online-Compiler -Seite.

Etwas verändern auch möglich, aber den regulären Ausdruck vermeiden. Zeichen für Zeichen durchgehen, den längsten bereich finden, der keine zeichen enthält, und wenn zeichen drumherum gewesen ist, diese beibehalten. Oder alle bereiche sortieren und >= anzahl, aber weiter vorne.

Ich weiß nicht, ob irgendwelche fertigen Tools mit Umbrüchen in Datenfeldern klarkommen. Das könnte ein Problem werden. Falls ja, wäre das die zu bevorzugende Variante, weil es dir die Arbeit leichter macht.

Wenn nein, musst du versuchen, dich selbst dadurch zu hangeln.

Also dort wo der Datensatz einer Zeile anfängt die Felder mitzählen und den nächsten Umbruch dann als zu den Daten gehörig auffassen, wenn du noch nicht genug Felder eingelesen hast. Das geht auch beim zeilenweisen Einlesen, du musst dann nur die gelesenen Zeilen zu einer echten Zeile in einer Liste o.ä. aufsammeln.

[QUOTE=CyborgBeta]"^.?([^"]+).$"
.group(1);
RegEx findet den ersten “inneren” Bereich, in dem keine " sind, und wovor und wonach beliebig viele " stehen. ^ ode $ optional.
Mittige oder hintere können damit nicht gefunden werden. Grüße.

Edit: ```import java.util.regex.*;

public class HelloWorld{

 public static void main(String []args){
     Pattern p = Pattern.compile("^.*?([^\"]+).*$");
     Matcher m = p.matcher("\"\"\"test\"\"\"\"");
     if (m.find())
        System.out.println(m.group(1));
 }

}```

stimmt sogar, was “ich” mir ausgedacht hab. Ohne ? nimmt er zu viel. Mit .?$ oder .+$ streikt er. Getestet auf einer Java-Online-Compiler -Seite.[/QUOTE]

Ganz ehrlich, das Verhalten von RegEx ist mir oft ein wenig zu subtil, sobald es ein wenig komplizierter wird…

Wenn du alleine nicht klar kommst, kann ich dir gerne helfen, wenn du ein kleines, ausführbares Beispiel baust, dass eine Liste von Zeilen aufbaut, wie du sie aus deiner Datei lesen würdest, dann der Code kommt, den du bisher hast, und dann am besten auch noch eine Liste mit den Zeilen da wäre, wie sie sein sollten. Dann könnte man am Ende einfach vergleichen!

Es geht ja auch nicht nur um Anführungszeichen inmitten der begrenzenden Anführungszeichen.
In den Daten können ja zB auch Kommata vorkommen :slight_smile:

OpenCsv kommt übrigens sehr gut mit Zeilenumbrüchen innerhalb von CSV-Daten zurecht. Nutze ich selber für so ekelhafte Dateien.

Ich hätte mehr dazu schreiben sollen/müssen, so sorgt es vielleicht für Wirrnisse / kein konstruktiver Beitrag, aber ihr wisst ja, dass ich mit dem „RegEx“ und den anderen überfordert war, also zu dumm, und man jeden RegEx auch so stellen kann, dass ihn keiner mehr schafft, und das, obwohl ich doch nur 2-mal da war. :frowning:
Schönen Tag bei dem tollen Wetter.

Dann sollte unbedingt dieses genutzt werden.

Mal ausprobiert:


        private String s;
        private boolean braces;

        private Token(String s, boolean braces) {
            this.s = s;
            this.braces = braces;
        }

        @Override
        public String toString() {
            if (braces) {
                return '\"' + s + '\"';
            } else {
                return s;
            }
        }
    }

    public static String[] splitAndTrim(String s) {
        LinkedList<Token> llt = new LinkedList<Token>();
        Pattern p = Pattern.compile("^.+?(\"?)([^\"]{2,})(\"?).+$");
        String[] strArr = s.split(", ");
        for (String string : strArr) {
            Matcher m = p.matcher(string);
            m.find();
            if (!m.group(1).isEmpty() && !m.group(3).isEmpty()) {
                llt.add(new Token(m.group(2), true));
            } else {
                llt.add(new Token(m.group(2), false));
            }
        }
        String[] strArr2 = new String[llt.size()];
        int i = 0;
        for (Token token : llt) {
            strArr2[i++] = token.toString();
        }
        return strArr2;
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException /*, InterruptedException*/ {
        for (String string : splitAndTrim("\"hello\", \"world\", \" \" \" \"  cool  \" \" \" \"")) {
            System.out.println(string);
        }
    }```
Wo ist denn dabei das Problem? string.split() könnte man anpassen, zwischen zwei " sollten nicht mehr als ein Zeichen sein, der Inhalt sollte mind. zwei Zeichen enthalten, `[^\"]{2,}` ersetzen durch das, was innerhalb der "inneren" " (Inhalt) stehen darf; Text mit Zeilenumbrüchen kann ja einfach zu einem String gemacht werden.

Landei hat recht, wenn man es mit Pattern machen möchte, wird's kompliziert(er) und man muss mehr über die mögl. Eingabe wissen.

Das eine Problem zu lösen ist nicht schwer. Dazu gab es oben schon Ansätze. Das Problem ist, dass CSV-Dateien “beliebig” komplex werden können bezüglich des Parsings, so dass es sich einfach anbietet, dafür fertige Lösungen zu verwenden, solange man sich nicht sicher ist (indem man die Dateien etwa selbst erzeugt), dass dies nicht notwendig ist.

Ach, ich hab auch vergessen, oben muss es nicht genau so viele öffnende wie schließende "-Zeichen geben - sonst wäre das Prob ja ganz einfach.

Prob: Wann fängt der eigentliche Inhalt an, wie lang ist er, aus welchen Zeichen besteht er und was darf zwischen zwei " stehen?

In einer 3-mal geschachtelten Schleife + mind. 3 zustandsvariablen sieht das auch nicht besser aus und es müsste mit coninue X; break X; immer hin und her gegangen werden. :frowning:

Warum das Rad nochmal erfinden und es dann wahrscheinlich nicht mal richtig rund bekommen?