Suche nach String mit unbekannten characters

maxe

Mitglied
Hallo, Ich schreibe ein Programm, das in einem File nach einer Zeile sucht. Bei dieser Zeile sind jedoch einige Wörter unbekannt. Ich bin erstmal soweit, dass ich den File auslese und ansich kann das Programm auch bereits nach gewissen zeilen suchen. Jedoch nur nach Zeilen, die keine unbekannten character haben.
Java:
public static void main(String[] args) throws FileNotFoundException{
        FileSearch fileSearch = new FileSearch();
        fileSearch.parseFile("src/defaultpackage/Alice_im_Wunderland.txt", "das _ mir _ _ _ vor");
    }

public class FileSearch {

    public void parseFile(String fileName, String searchStr) throws FileNotFoundException {
        try {
            int x = 0;
            Scanner scan = new Scanner(new File(fileName));
            while (scan.hasNext()) {
                String line = scan.nextLine().toLowerCase().toString();
                entferneunterzeichen(line);
                if (line.contains(searchStr)) {
                    System.out.println(line);
                    x = 1;
                }
            }
            if (x != 1) {
                System.out.println("Diese Zeile gibt es nicht.");
            }
        } catch (FileNotFoundException e) {
            System.err.println("Datei nicht gefunden!");
        }
    }

    public String entferneunterzeichen(String line) {
        String re = null;
        for (int i = 0; i < line.length(); i++) {
            if (line.charAt(i) != '_') {
                re += line.charAt(i);
            }
        }
        return re;
    }
}
 
"re" wird in these Methode ganz am Anfang initialisiert.
Schau die mal an, was sie mit den einzelnen Zeichen von "line" macht (auch wenn sehr ineffizient)

Mach's am Besten auf Papier. Schreib einen kurzen Text als Line-Variablen Blockbuchstaben auf, Stell auch sicher, dass dieser Text einen oder mehrere Unterstriche hat. Darunter screibe ein leeres "re" und versuch mal, anhand der Schritte, die in der Methode stehen nachzuvollziehen, wie sich re im Laufe der Methode verändert

Im Anschluss:
So, oder so ... Füttere die Methode mal mit einer "line", die Unterstriche enthält, mit dem gleichen Code wie in deiner parseFile-Methode.
Schau, ob und wie sich vor und nach dem Aufruf der Methode "line" verändert hat. Entspricht es dem, was du vorher auf Papier gemacht hast?
Warum ist das wohl so?
 
ps: Noch was. Nachdem du rausgefunden hast, was die nicht von dir geschriebene Methode macht, schreib Dokumentation dazu.
Java:
/**
 * Diese Methode macht ...
 * @param line Beschreibung des Eingangsparameters
 * @return Beschreibung des Rückgabewerts
 */
public String entferneunterzeichen(String line) {
    ...
}

Grund: Dann brauchst du beim nächsten Mal nicht mehr die Methode analysieren, sondern nur noch die Beschreibung lesen.
 
"re" wird in these Methode ganz am Anfang initialisiert.
Schau die mal an, was sie mit den einzelnen Zeichen von "line" macht (auch wenn sehr ineffizient)

Mach's am Besten auf Papier. Schreib einen kurzen Text als Line-Variablen Blockbuchstaben auf, Stell auch sicher, dass dieser Text einen oder mehrere Unterstriche hat. Darunter screibe ein leeres "re" und versuch mal, anhand der Schritte, die in der Methode stehen nachzuvollziehen, wie sich re im Laufe der Methode verändert

Im Anschluss:
So, oder so ... Füttere die Methode mal mit einer "line", die Unterstriche enthält, mit dem gleichen Code wie in deiner parseFile-Methode.
Schau, ob und wie sich vor und nach dem Aufruf der Methode "line" verändert hat. Entspricht es dem, was du vorher auf Papier gemacht hast?
Warum ist das wohl so?
wenn ich das richtig verstehe, kommt nach H_llo, am ende Hllo raus oder?
 
Da jeder der Unterstriche von Leerzeichen umschlossen ist, kannst du einfach die Textzeile und den Suchstring jeweils in Arrays zerlegen. Trenner ist das Leereichen. Dann musst du einfach nur die Elemente der beiden Arrays vergleichen, bei welchem im Suchstring/Array keine Unterstriche sind.
 
Da jeder der Unterstriche von Leerzeichen umschlossen ist, kannst du einfach die Textzeile und den Suchstring jeweils in Arrays zerlegen. Trenner ist das Leereichen. Dann musst du einfach nur die Elemente der beiden Arrays vergleichen, bei welchem im Suchstring/Array keine Unterstriche sind.
😮daran hab ich nicht gedacht. Danke, ich werde es ausprobieren
 
Sollten die Arrays aus Suchstring und Textzeile unterschiedlich lang sein, dann kannst du schon weitermachen und musst die Zeile nicht weiter prüfen.
 
Ich bin davon ausgegangen, das der TE noch keinen Plan von Regex hat, da Scanner verwendet wird um eine Datei zeilenweise zu lesen.
 
Einfach mal schnell "quick and dirty"
Java:
        String lineTemplate = "das _ mir _ _ _ vor";
        lineTemplate = lineTemplate.replace("_", "(\\S*)");
        final Pattern pattern = Pattern.compile(lineTemplate);

        try (BufferedReader reader = Files.newBufferedReader(Path.of("Alice_im_Wunderland.txt"))) {
            final List<String> filteredLines = reader.lines().filter(s -> pattern.matcher(s).matches()).toList();
            if (filteredLines.isEmpty()) {
                System.out.println("Suchmuster nicht gefunden!");
            } else {
                filteredLines.forEach(System.out::println);
            }
        } catch (final IOException e) {
            System.err.println("Fehler beim lesen der Datei!");
            e.printStackTrace();
        }
Normalerweise würde man das sauber in Methoden packen und die Rückgabe auswerten, statt System.out.println
 
warum ist diese Variante besser anstelle eines scanners?
Einfach mal schnell "quick and dirty"
Java:
        String lineTemplate = "das _ mir _ _ _ vor";
        lineTemplate = lineTemplate.replace("_", "(\\S*)");
        final Pattern pattern = Pattern.compile(lineTemplate);

        try (BufferedReader reader = Files.newBufferedReader(Path.of("Alice_im_Wunderland.txt"))) {
            final List<String> filteredLines = reader.lines().filter(s -> pattern.matcher(s).matches()).toList();
            if (filteredLines.isEmpty()) {
                System.out.println("Suchmuster nicht gefunden!");
            } else {
                filteredLines.forEach(System.out::println);
            }
        } catch (final IOException e) {
            System.err.println("Fehler beim lesen der Datei!");
            e.printStackTrace();
        }
Normalerweise würde man das sauber in Methoden packen und die Rückgabe auswerten, statt System.out.println
 
warum ist diese Variante besser anstelle eines scanners?

  • BufferedReader is synchronous while Scanner is not. BufferedReader should be used if we are working with multiple threads.
  • BufferedReader has a significantly larger buffer memory than Scanner.
  • The Scanner has a little buffer (1KB char buffer) as opposed to the BufferedReader (8KB byte buffer), but it’s more than enough.
  • BufferedReader is a bit faster as compared to Scanner because the Scanner does the parsing of input data and BufferedReader simply reads a sequence of characters.
Man kann das Parsen des Scanners natürlich auch als Vorteil nutzen, wenn man die Struktur der Datei genau kennt. Allerdings vermischt man dann Logik mit Input.
Ich folge dem Prinzip: Zuerst einlesen, dann auswerden - oder zumindest das Einlesen immer "raw" und dann die eingelesenen Werte weiterleiten an die Logik.
 
warum ist diese Variante besser anstelle eines scanners?
Nein das ist nicht besser. Scanner ist eben eine Klasse, welche typischerweise in Anfängerkursen verwendet wird. Viele Leute sind gewohnt BufferedReader für Textdateien zu verwenden. Scanner ist weder schlecht noch langsam. Historisch gesehen stand Scanner früher in dem Ruf langsam und Speicherhungrig zu sein, da darin sehr viel Regex verwendet wird. Die Geschwindigkeit und Sicherheit von Regex ist aber viel besser geworden.
 
Ich komme mir zwar irgendwie blöd vor, dass ich hier ständig fragen muss aber ich weiß momentan nicht wirklich weiter. Der Teil, der gesucht werden soll, ist auch in einer extra datei. Das splitten funktioniert hier nicht wirklich. kann sich das mal schnell jmd anschauen?
Java:
public static String re = "";

    public static void stoerung1() throws IOException {

        try (BufferedReader br = new BufferedReader(new FileReader("src/defaultpackage/stoerung0.txt"))) {

            for (String line; (line = br.readLine()) != null;) {
                for (int i = 0; i < line.length(); i++) {
                    entferneunterzeichen(line);
                    String[] lineSplit = re.split(" ");
                    String lineArr = lineSplit[i];
                    System.out.println(lineArr);
                }
            }
        }
    }

    public static String entferneunterzeichen(String line) {
        for (int i = 0; i < line.length(); i++) {
            if (line.charAt(i) != '_') {
                re += line.charAt(i);
            }
        }
        return re;

    }
}
Ich bin erstmal so weit. Angehangen ist die datei. Es kommen zu viele leerzeilen, bei denen ich denke, dass sie auch in den Array aufgenommen werden.
 

Anhänge

Mein Tipp ist, static wirklich nur minimal zu nutzen. Also die main Methode ist natürlich static. Wenn Du Konstanten hast, dann sind diese static (und final). Aber so Code wie Du hier zeigst ist extrem fehlerträchtig. Du hast eine statische Variable re die an diversen Stellen verändert werden. Das ist extrem fehleranfällig und auf den ersten Blick scheint mir, dass dieser String immer nur anwächst.

Dann ganz viele Code Smells: Du hast eine Methode, die etwas zurück gibt, aber das interessiert Dich nicht (Das steht dann ja in einer statischen Variable) ..

Also wenn Du statische Methoden hast, dann haben die bitte auf keinen Fall ein state! Also keine Abhängigkeit zu irgendwelchen statischen Variablen oder so!

Nur dieser eine Punkt beachtet wäre dann z.B.:
Java:
    public static void stoerung1() throws IOException {

        try (BufferedReader br = new BufferedReader(new FileReader("src/defaultpackage/stoerung0.txt"))) {

            for (String line; (line = br.readLine()) != null;) {
                for (int i = 0; i < line.length(); i++) {
                    String re = entferneunterzeichen(line);
                    String[] lineSplit = re.split(" ");
                    String lineArr = lineSplit[i];
                    System.out.println(lineArr);
                }
            }
        }
    }

    public static String entferneunterzeichen(String line) {
        String re = "";
        for (int i = 0; i < line.length(); i++) {
            if (line.charAt(i) != '_') {
                re += line.charAt(i);
            }
        }
        return re;

    }

==> keine globale Variable re. Das sind jetzt lokale Variablen. In der ersten Methode wird dies aus der Rückgabe nitialisiert. In der zweiten Methode ist das dann eine lokale Variable. Damit wird bei jedem Aufruf immer wieder mit dem leeren String gestartet und nicht immer direkt angehangen.

Aber da sind noch andere Probleme: Du hast eine Schleife, die bis i < line.length geht. Aber Du greifst dann auf einen lineSplit[i] zu? Das kann nur falsch sein. Bespiel ist eine Zeile: "Hallo welt" - das hat eine Länge von 10. Bei einem split bekommst Du aber nur ein Array mit "Hallo" und "welt" - also index 0 und 1 - durch die äußere Schleife würdest Du aber auf Indizes 0...9 zugreifen.

Hier wäre der nächste Tipp: Bei Schleifen wo die Zählvariable als Index verwendet wird: Dann muss die Schleifenbedingung die Indexbegrenzung sein!

Teile so Code sauber in viele Teilmethode. Das führt zu deutlich besser lesbaren Code und erleichtert die Fehlersuche.

Edit: Ediiert um das [i] sichtbar zu machen.
 
Zuletzt bearbeitet:
Mein Tipp ist, static wirklich nur minimal zu nutzen. Also die main Methode ist natürlich static. Wenn Du Konstanten hast, dann sind diese static (und final). Aber so Code wie Du hier zeigst ist extrem fehlerträchtig. Du hast eine statische Variable re die an diversen Stellen verändert werden. Das ist extrem fehleranfällig und auf den ersten Blick scheint mir, dass dieser String immer nur anwächst.

Dann ganz viele Code Smells: Du hast eine Methode, die etwas zurück gibt, aber das interessiert Dich nicht (Das steht dann ja in einer statischen Variable) ..

Also wenn Du statische Methoden hast, dann haben die bitte auf keinen Fall ein state! Also keine Abhängigkeit zu irgendwelchen statischen Variablen oder so!

Nur dieser eine Punkt beachtet wäre dann z.B.:
Java:
    public static void stoerung1() throws IOException {

        try (BufferedReader br = new BufferedReader(new FileReader("src/defaultpackage/stoerung0.txt"))) {

            for (String line; (line = br.readLine()) != null;) {
                for (int i = 0; i < line.length(); i++) {
                    String re = entferneunterzeichen(line);
                    String[] lineSplit = re.split(" ");
                    String lineArr = lineSplit[i];
                    System.out.println(lineArr);
                }
            }
        }
    }

    public static String entferneunterzeichen(String line) {
        String re = "";
        for (int i = 0; i < line.length(); i++) {
            if (line.charAt(i) != '_') {
                re += line.charAt(i);
            }
        }
        return re;

    }

==> keine globale Variable re. Das sind jetzt lokale Variablen. In der ersten Methode wird dies aus der Rückgabe nitialisiert. In der zweiten Methode ist das dann eine lokale Variable. Damit wird bei jedem Aufruf immer wieder mit dem leeren String gestartet und nicht immer direkt angehangen.

Aber da sind noch andere Probleme: Du hast eine Schleife, die bis i < line.length geht. Aber Du greifst dann auf einen lineSplit zu? Das kann nur falsch sein. Bespiel ist eine Zeile: "Hallo welt" - das hat eine Länge von 10. Bei einem split bekommst Du aber nur ein Array mit "Hallo" und "welt" - also index 0 und 1 - durch die äußere Schleife würdest Du aber auf Indizes 0...9 zugreifen.

Hier wäre der nächste Tipp: Bei Schleifen wo die Zählvariable als Index verwendet wird: Dann muss die Schleifenbedingung die Indexbegrenzung sein!

Teile so Code sauber in viele Teilmethode. Das führt zu deutlich besser lesbaren Code und erleichtert die Fehlersuche.
Danke, ich werde die Hinweise umsetzten. Dennoch ist meine Frage damit nicht wirklich beatwortet.
 
und mit ihrer Variante, bekomme ich einen ArrayIndexOutOfBoundsexception. Jedoch ist hier dann bloß einmal
Ich habe diese Problematik ja doch erläutert. Bei Deiner Variante kommen beide Probleme zusammen und durch Zufall kommt daher eben diese Exception nicht.

Vielleicht macht es Sinn, den Algorithmus erst einmal sauber zu formulieren, ehe Du versuchst, irgendwas zu programmieren.

Die ganzen Leerzeilen kommen wohl einfach durch das Ergebnis vom Split. Du hast in der Datei ja:
"das _ mir _ _ _ vor"

Wenn Du nur die _ entfernst, dann hast Du:
"das mir vor"
Und nun an Leerzeichen getrennt ergibt:
"das", "", "mir", "", "", "", "vor"

Und da Du ja immer an das re die Zeile anhängst, wird da in der inneren Schleife beim ersten Durchlauf ein
"das mir vor" in re sein. Dann "das mir vordas mir vor" und dann "das mir vordas mir vordas mir vor" u.s.w.

kannst du hier bitte noch einmal genauer erklären, was damit gemeint ist?
Du hast eine Schleife, die über die Zeichen einer Zeile gehen. Aber den Schleifenzähler nutzt Du zum Zugreifen auf ein Array.
Nimm einfach einmal an, in der Datei hättest nur eine Zeile mit 20 a hintereinander:
"aaaaaaaaaaaaaaaaaaaa"
Die Schleife geht also von i=0 bis i<20.
Split ergibt ein array mit genau einem Element: "aaaaaaaaaaaaaaaaaaaa"

Und nun versuchst Du in der Schleife auf die Elemente 0...19 zuzugreifen. Das bringt so nichts. Also wenn, dann kannst Du eine Zeile auslesen, diese dann splitten und dann über das Array laufen.
 
Ok, ich denke ich habe das Problem jetzt verstanden jedoch weiß ich nicht, wie es im code umsetzen soll, dass die Zeile ausgelesen, dann gesplittet und dann in einen Array umgewandelt werden soll.
 
Das hast Du doch alles schon im Code.

  • Du liest ja die Zeile ein
  • die Schleife über die Länge der Zeile ist natürlich quatsch
  • Du entfernst dann die _ -> Wieso? Die haben doch eine Bedeutung oder nicht? Das geht aber auch über String.replaceAll("_", "") daher ist da keine eigene Methode notwendig.
  • Du rufst split auf - wenn Du mehrere Leerzeichen zusammen als ein Trenner haben willst, dann geht das über ein .split(" +");

Split nimmt ein regulären Ausdruck und daher kann man da mit dem + sagen, dass es ein oder mehrere Leerzeichen sein können.
 
Oder einmal direkt als Ergebnis, wie dann der Code aussehen könnte:
Java:
    public static void stoerung1() throws IOException {
        try (BufferedReader br = new BufferedReader(new FileReader("src/defaultpackage/stoerung0.txt"))) {
            for (String line; (line = br.readLine()) != null;) {
                String re = line.replaceAll("_", "");
                String[] lineSplit = re.split(" +");
                // Hier hast Du jetzt in lineSplit nur die Worte der Zeile.
                System.out.println(Arrays.toString(lineSplit));
            }
        }
    }
 
Das hast Du doch alles schon im Code.

  • Du liest ja die Zeile ein
  • die Schleife über die Länge der Zeile ist natürlich quatsch
  • Du entfernst dann die _ -> Wieso? Die haben doch eine Bedeutung oder nicht? Das geht aber auch über String.replaceAll("_", "") daher ist da keine eigene Methode notwendig.
  • Du rufst split auf - wenn Du mehrere Leerzeichen zusammen als ein Trenner haben willst, dann geht das über ein .split(" +");

Split nimmt ein regulären Ausdruck und daher kann man da mit dem + sagen, dass es ein oder mehrere Leerzeichen sein können.
die Schleife über die länge der Zeile habe ich beunutzt, damit ich bei dem split das "i" als value für den Array habe.
wenn ich die Schleife jetzt entferne funktioniert das schließlich nichtmehr
 
die Schleife über die länge der Zeile habe ich beunutzt, damit ich bei dem split das "i" als value für den Array habe.
wenn ich die Schleife jetzt entferne funktioniert das schließlich nichtmehr
Was genau willst du denn machen? Wie schon geschrieben macht es so einfach keinen Sinn.

Daher noch einmal zu dem ganz wichtigen Punkt:
Vielleicht macht es Sinn, den Algorithmus erst einmal sauber zu formulieren, ehe Du versuchst, irgendwas zu programmieren.

Wenn man etwas programmieren will, dann sollte man sich vorher genau überlegen, wie die Zusammenhänge und wie der Lösungsweg ist.
 
Ich habe jetzt etwas ausprobiert. auch wenn dir der code vermutlich nicht gefallen wird möchte ich fragen, ob du weißt, woran hier der Fehler liegt. Es wird eine ArrayIndexOutOfBoundsException bei Zeile 33 ausgegeben.
Java:
public class StoerungSearch {

     public static String[] lineSplit = null;
     public static int length;
   
    public static String[] stoerung0() throws IOException {
     
        try (BufferedReader br = new BufferedReader(new FileReader("src/defaultpackage/stoerung0.txt"))) {
            for (String line; (line = br.readLine()) != null;) {
                String re = line.replaceAll("_", "");
                lineSplit = re.split(" +");
                length = re.length();
            }
        }
        return lineSplit;
    }
   
    public class FileSearch {

    public void parseFile0(String fileName) throws FileNotFoundException, IOException {
        StoerungSearch.stoerung0();
        String lines = null;
        try {
            int x = 0;
            Scanner scan = new Scanner(new File(fileName));
            while (scan.hasNext()) {
                String line = scan.nextLine().toLowerCase().toString();
                lines = scan.nextLine().toLowerCase().toString();
                String[] lineSplit = line.split(" +");

                for (int i = 0; i < lines.length(); i++) {
                    for (int j = 0; j < StoerungSearch.length; j++) {
                        if (lineSplit[i] == StoerungSearch.lineSplit[j]) {
                            x = 1;
                        }
                    }
                }
            }
            if (x != 1) {
                System.out.println("Diese Zeile gibt es nicht.");
            } else {
                System.out.println(lines);
            }
        } catch (FileNotFoundException e) {
            System.err.println("Datei nicht gefunden!");
        }
    }
}
Ich vergleiche quasi jeden String von dem Original mit Jedem der Strings von der Störung. Mein ziel ist das, wenn alle Strings mit jeweils einem der Strings aus dem Original, die in derselben line sind, zusammen passen, am Ende die Zeile des Originals ausgegeben wird.
 
Zuletzt bearbeitet:
a) in Zeile 27 ist keine Array Operation, daher kann es da keine solche Exception geben.

b) Strings vergleicht man mit equals

c) Wenn Du da eine Zeile aufsplittest, warum setzt du die Länge auf die Länge der zeile? Du hast eine Zeile von z.B. 50 Zeichen länge. Dann teilst Du diese auf in 8 Wörter. Wenn Du dann die 8 Wörter durch gehen willst, dann machst Du keine Schleife bis 50!

d) Beschreibe den Algorithmus als erstes, den Du umsetzen willst. Ich habe das Gefühl, dass Du relativ planlos probierst.
 
Ich habe jetzt etwas ausprobiert. auch wenn dir der code vermutlich nicht gefallen wird möchte ich fragen, ob du weißt, woran hier der Fehler liegt. Es wird eine ArrayIndexOutOfBoundsException bei Zeile 33 ausgegeben.
Java:
public class StoerungSearch {

     public static String[] lineSplit = null;
     public static int length;
  
    public static String[] stoerung0() throws IOException {
    
        try (BufferedReader br = new BufferedReader(new FileReader("src/defaultpackage/stoerung0.txt"))) {
            for (String line; (line = br.readLine()) != null;) {
                String re = line.replaceAll("_", "");
                lineSplit = re.split(" +");
                length = re.length();
            }
        }
        return lineSplit;
    }
  
    public class FileSearch {

    public void parseFile0(String fileName) throws FileNotFoundException, IOException {
        StoerungSearch.stoerung0();
        String lines = null;
        try {
            int x = 0;
            Scanner scan = new Scanner(new File(fileName));
            while (scan.hasNext()) {
                String line = scan.nextLine().toLowerCase().toString();
                lines = scan.nextLine().toLowerCase().toString();
                String[] lineSplit = line.split(" +");

                for (int i = 0; i < lines.length(); i++) {
                    for (int j = 0; j < StoerungSearch.length; j++) {
                        if (lineSplit[i] == StoerungSearch.lineSplit[j]) {
                            x = 1;
                        }
                    }
                }
            }
            if (x != 1) {
                System.out.println("Diese Zeile gibt es nicht.");
            } else {
                System.out.println(lines);
            }
        } catch (FileNotFoundException e) {
            System.err.println("Datei nicht gefunden!");
        }
    }
}
Ich vergleiche quasi jeden String von dem Original mit Jedem der Strings von der Störung. Mein ziel ist das, wenn alle Strings mit jeweils einem der Strings aus dem Original, die in derselben line sind, zusammen passen, am Ende die Zeile des Originals ausgegeben wird.
musste hier noch etwas verändern bei dem format liegt der fehler bei Zeile 33
 
musste hier noch etwas verändern bei dem format liegt der fehler bei Zeile 33
Siehe Punkt c) bzw das, was ich vorher schon erläutert habe.

Was Du machst: Du hast 300 Euro in 100€ Geldscheinen. Das teilst Du auf in Haufen - also hast Du da drei Haufen aus jeweils einem 100€ Geldschein. Und da es ja 300€ sind, versuchst du nun, auf 300 Haufen zuzugreifen. Du hast aber doch nur 3 Haufen!
 
Siehe Punkt c) bzw das, was ich vorher schon erläutert habe.

Was Du machst: Du hast 300 Euro in 100€ Geldscheinen. Das teilst Du auf in Haufen - also hast Du da drei Haufen aus jeweils einem 100€ Geldschein. Und da es ja 300€ sind, versuchst du nun, auf 300 Haufen zuzugreifen. Du hast aber doch nur 3 Haufen!
das habe ich bereits gefixed denke ich. denoch kommt der fehler weiterhin
 
Java:
 public void parseFile0(String fileName) throws FileNotFoundException, IOException {
        StoerungSearch.stoerung0();
        String lines = null;
        try {
            int x = 0;
            Scanner scan = new Scanner(new File(fileName));
            while (scan.hasNext()) {
                String line = scan.nextLine().toLowerCase().toString();
                lines = scan.nextLine().toLowerCase().toString();
                String[] lineSplit = lines.split(" +");

                for (int i = 0; i < line.length(); i++) {
                    for (int j = 0; j < StoerungSearch.length; j++) {
                        if (lineSplit[i].equals(StoerungSearch.lineSplit[j])) {
                            x = 1;
                        }
                    }
                }
            }
            if (x != 1) {
                System.out.println("Diese Zeile gibt es nicht.");
            } else {
                System.out.println(lines);
            }
        } catch (FileNotFoundException e) {
            System.err.println("Datei nicht gefunden!");
        }
    }
so sieht nun der code aus
 
Sorry, aber ich weiss nicht, was ich noch sagen soll:
line.length -> Länge der Zeile ("300€ insgesamt") (Ebenso StoerungSearch.length so nicht geändert!)
lineSplit -> Array mit Worten ("3 Haufen a 1 100€ Schein") (Ebenso StoerungSearch.lineSplit)

Also das, was ich von Anfang an gesagt habe: Du willst über ein Array Iterieren, dann greif direkt auf die Länge des Arrays zu! Die ganzen Probleme, die Du jetzt hier hattest sollten doch so langsam genug Anreiz sein, so ein Best Practice zu machen alleine schon, weil Du merkst, was Du sonst für Probleme hast!

Also:
Java:
                for (int i = 0; i < lineSplit.length; i++) {
                    for (int j = 0; j < StoerungSearch.lineSplit.length; j++) {
                        if (lineSplit[i].equals(StoerungSearch.lineSplit[j])) {
                            x = 1;
                        }
                    }
                }

Damit hast Du dann zwei Schleifen, die keine ArrayIndexOutOfBoundsException werden werden.

Das aber nur konkret zu dem Problem mit der Exception. Ändert nichts daran, dass ich nicht sehe, wohin das führen soll (wenn ich mir den Start des Threads ansehe und daher sehe, was da so vermutlich von Dir gewünscht wird).
 
Sorry, aber ich weiss nicht, was ich noch sagen soll:
line.length -> Länge der Zeile ("300€ insgesamt") (Ebenso StoerungSearch.length so nicht geändert!)
lineSplit -> Array mit Worten ("3 Haufen a 1 100€ Schein") (Ebenso StoerungSearch.lineSplit)

Also das, was ich von Anfang an gesagt habe: Du willst über ein Array Iterieren, dann greif direkt auf die Länge des Arrays zu! Die ganzen Probleme, die Du jetzt hier hattest sollten doch so langsam genug Anreiz sein, so ein Best Practice zu machen alleine schon, weil Du merkst, was Du sonst für Probleme hast!

Also:
Java:
                for (int i = 0; i < lineSplit.length; i++) {
                    for (int j = 0; j < StoerungSearch.lineSplit.length; j++) {
                        if (lineSplit[i].equals(StoerungSearch.lineSplit[j])) {
                            x = 1;
                        }
                    }
                }

Damit hast Du dann zwei Schleifen, die keine ArrayIndexOutOfBoundsException werden werden.

Das aber nur konkret zu dem Problem mit der Exception. Ändert nichts daran, dass ich nicht sehe, wohin das führen soll (wenn ich mir den Start des Threads ansehe und daher sehe, was da so vermutlich von Dir gewünscht wird).
Also gut:
1. was wäre deine Vorgehensweise bei dem Problem.
2. Wenn ich den Code schnipsel bei mir einsetze, bekomme ich zwar keine ArrayIndexOutOfBoundsException mehr, jedoch eine NoSuchElementException: No line found Exception.Ich habe gerade einiges auprobiert. dennoch bekomme ich sie nicht weg.
 
1. was wäre deine Vorgehensweise bei dem Problem.
Das habe ich bereits mehrfach erwähnt: Ehe man überhaupt nur eine Zeile Code schreibt, setzt man sich hin und überlegt sich, wie das Problem zu lösen ist. Ein Algorithmus entsteht nicht in Code. Es beginnt immer mit einer Analyse des Problems und einer Lösungsstrategie. Da führt schlicht kein Weg dran rum.

2. Wenn ich den Code schnipsel bei mir einsetze, bekomme ich zwar keine ArrayIndexOutOfBoundsException mehr, jedoch eine NoSuchElementException: No line found Exception.Ich habe gerade einiges auprobiert. dennoch bekomme ich sie nicht weg.
Keine Ahnung, was Du da dann genau an Code hast und auch der Fehler sagt mir nichts. Du hat irgend einen Code zusammen gestrickt, bei dem ich nicht einmal sehe, wie dieser bei dem eigentlichen Problem
Hallo, Ich schreibe ein Programm, das in einem File nach einer Zeile sucht. Bei dieser Zeile sind jedoch einige Wörter unbekannt.
wirklich helfen sollen. Daher sind das zwar paar generelle Punkte, die ich anbringen kann, aber die werden nur das konkrete Problem beheben (hier das ArrayOutOfBoundsException) aber dies führt nicht plötzlich zu einem Algorithmus, der eben die eigentliche Problematik löst. Das sind also lediglich Dinge, die ausgeführt wurden von mir, weil es generelle Dinge waren, die unabhängig von der Hauptthematik waren.
 
Das habe ich bereits mehrfach erwähnt: Ehe man überhaupt nur eine Zeile Code schreibt, setzt man sich hin und überlegt sich, wie das Problem zu lösen ist. Ein Algorithmus entsteht nicht in Code. Es beginnt immer mit einer Analyse des Problems und einer Lösungsstrategie. Da führt schlicht kein Weg dran rum.


Keine Ahnung, was Du da dann genau an Code hast und auch der Fehler sagt mir nichts. Du hat irgend einen Code zusammen gestrickt, bei dem ich nicht einmal sehe, wie dieser bei dem eigentlichen Problem

wirklich helfen sollen. Daher sind das zwar paar generelle Punkte, die ich anbringen kann, aber die werden nur das konkrete Problem beheben (hier das ArrayOutOfBoundsException) aber dies führt nicht plötzlich zu einem Algorithmus, der eben die eigentliche Problematik löst. Das sind also lediglich Dinge, die ausgeführt wurden von mir, weil es generelle Dinge waren, die unabhängig von der Hauptthematik waren.
Hi, da ich heute noch etwas Zeit hatte, konnte ich meine Frage nocheimal exakter formulieren. Siehe pngjavaforum-frage.png
 
Das ist der codeabteil in dem ich das machen möchte
Java:
while (scan.hasNext()) {
                line = scan.nextLine().toLowerCase().toString();

                String[] lineSplit = line.split(" +");

                for (int i = 0; i < lineSplit.length ; i++) {
                    for (int j = 0; j < StoerungSearch.lineSplit.length; j++) {
                        if (lineSplit[i].equals(StoerungSearch.lineSplit[j])) {
                                output = output + " " + line;                        
                            x = 1;

                        }
                    }
                }
Funktionieren tut es noch immer nicht und ich weiß auch den Grund: sobald das erste Wort aus der störung übereinstimmt wird die line ausgegeben.
 
Da nur ein paar Fragen von meiner Seite. Du hast ja als Suchstring:
"Hallo _ _ Welt"

Wo soll das alles reagieren?

"Hallo Du schöne Welt" ist klar -> das ist ein Match
"Hallo Welt" -> Da wurden die _ ignoriert
"Welt Hallo" -> Da stimmt sogar die Reihenfolge nicht!
...

Das ist also relativ deutlich.

Wenn Du alle Wörter des Suchstrings mit allen Wörtern der Zeile vergleichst, dann kann sogar ein einfaches "Hallo" oder "Welt" matchen, also bei
"Was für eine blöde Welt" oder "Ich habe Hallo gesagt" würden dann schon gefunden werden.

Es muss also mehrere Übereinstimmungen geben:
1. Hallo
2. beliebiges Wort
3. beliebiges Wort
4. Welt

Also als erstes musst Du es schaffen, dass Du dies so erkennen kannst. Da gibt es viele Wege. Da Du bereits etwas hattest mit _ entfernen kann man das nutzen:
a) Als erstes ersetzen wir alle Whitespace durch ein Leerzeichen. Also wenn da etwas steht wie "Hallo Welt" dann wird daraus ein "Hallo Welt" ==> replaceAll("\\s+", " ");
b) Dann löschen wir die "" => repalceAll("", "");
c) Dann ein split(" ") und wir bekommen als Resultat bei "Hallo _ _ Welt" ein "Hallo", "", "", "Welt"

Damit hätten wir eine Datenform für unseren Suchstring. Der leere String steht also für ein beliebiges Wort.

Dann ist die Frage, wie wir jetzt Treffer finden. Dazu kann eine Zeile ja irgendwas enthalten. Also z.B. ein:
"Ich programmiere Java. Hallo schöne Java Welt"
Aufteilen in Worte - dabei merken wir hier schon: Bei Satzzeichen müssen wir aufpassen! Wir wollen daraus bekommen:
"Ich", "programmiere", "Java", "Hallo", "schöne", "Java", "Welt"

Also zusammengefasst:
"Ich", "programmiere", "Java", "Hallo", "schöne", "Java", "Welt"
soll durchsucht werden.

Gesucht wird: "Hallo", "", "", "Welt" mit "" steht für ein beliebiges Wort!

Es geht also um das Finden einer Sequenz! Damit die Sequenz überein stimmt, muss ab einer Stelle alle Elemente überein stimmen. Das kann man also einfach machen:
Ich gehe die Sequenz durch vom 0ten Wort bis hin zu (Anzahl-AnzahSuchsequenz)
Wieso diese hintere Grenze: Wenn ich eine Sequenz von 4 Worten suche, dann kann ich aufhören zu suchen, wenn nur noch 3 da sind!

Also fange ich an beim ersten Wort: "Ich" -> Ist das der Anfang der Sequenz? Nein.
"programmiere" -> Nicht Anfang der Sequenz
"Java" -> Nicht Anfang der Sequenz.
"Hallo" -> Ja, Anfang der Sequenz!
--> "schöne" -> Ja, ist in Sequenz (da "" = beliebiges Wort!)
--> "Java" -> Ja, ist in Sequenz (da "" = beliebiges Wort!)
--> "Welt" -> Ja, ist in Sequenz, Sequenz abgeschlossen! Treffer auf der Zeile!

Wir müssen natürlich weitere Testfälle. Was ist mit "Hallo schöne Java Sprache"?
"Hallo" -> Ja, Anfang der Sequenz!
--> "schöne" -> Ja, ist in Sequenz (da "" = beliebiges Wort!)
--> "Java" -> Ja, ist in Sequenz (da "" = beliebiges Wort!)
--> "Sprache" -> Nein, nicht in Sequenz! ==> Hier geht es dann mit der äußeren Schleife weiter:
"schöne" -> Nicht Anfang der Sequenz
...

Das wäre ein Vorgehen das möglich sein könnte. Ist noch etwas oberflächig. Das muss man dann genauer formulieren. Im Code selbst wäre tatsächlich eine Methode a.la. "checkSequence" oder so, die dann prüft: Ist es ein Anfang der Sequenz.
Und da wird dann ein Wort geprüft. Also sowas wie boolean checkWords(String search, String found) was dann prüft:
Ist search leer? Dann passt es (da beliebiges Wort akzeptiert wird!)
Wenn search nicht leer ist, dann werden die Worte verglichen (equals oder equalsIgnoreCase).

So wäre ein mögliches Vorgehen. Einmal etwas erläutert, denn das ist halt das, was man sich etwas hätte erarbeiten müssen. Angefangen von: Was sagt mir die Eingabe? Bis hin zu einem Vorgehen ("Ich prüfe, ob die Sequenz ab demn Punkt startet / vorhanden ist"). Das erste ist Verständnis der Aufgabe. Das zweite ist das Finden eines Lösungsweges. Und da hilft oft Stift und Papier. Ohne geht es auch bei mir nicht. Das wichtigste Werkzeug in Designmeetings und so ist und bleibt das Whiteboard. Man spielt Dinge durch. (Das ist dann natürlich ein anderes Noiveau, aber generell werden Abläufe / Anforderungen verstanden, dokumentiert und dann umgesetzt. Ohne Abläufe / Anforderungen geht es nicht, denn das fließt auch direkt in die Tests ein!)
 
Da nur ein paar Fragen von meiner Seite. Du hast ja als Suchstring:
"Hallo _ _ Welt"

Wo soll das alles reagieren?

"Hallo Du schöne Welt" ist klar -> das ist ein Match
"Hallo Welt" -> Da wurden die _ ignoriert
"Welt Hallo" -> Da stimmt sogar die Reihenfolge nicht!
...

Das ist also relativ deutlich.

Wenn Du alle Wörter des Suchstrings mit allen Wörtern der Zeile vergleichst, dann kann sogar ein einfaches "Hallo" oder "Welt" matchen, also bei
"Was für eine blöde Welt" oder "Ich habe Hallo gesagt" würden dann schon gefunden werden.

Es muss also mehrere Übereinstimmungen geben:
1. Hallo
2. beliebiges Wort
3. beliebiges Wort
4. Welt

Also als erstes musst Du es schaffen, dass Du dies so erkennen kannst. Da gibt es viele Wege. Da Du bereits etwas hattest mit _ entfernen kann man das nutzen:
a) Als erstes ersetzen wir alle Whitespace durch ein Leerzeichen. Also wenn da etwas steht wie "Hallo Welt" dann wird daraus ein "Hallo Welt" ==> replaceAll("\\s+", " ");
b) Dann löschen wir die "" => repalceAll("", "");
c) Dann ein split(" ") und wir bekommen als Resultat bei "Hallo _ _ Welt" ein "Hallo", "", "", "Welt"

Damit hätten wir eine Datenform für unseren Suchstring. Der leere String steht also für ein beliebiges Wort.

Dann ist die Frage, wie wir jetzt Treffer finden. Dazu kann eine Zeile ja irgendwas enthalten. Also z.B. ein:
"Ich programmiere Java. Hallo schöne Java Welt"
Aufteilen in Worte - dabei merken wir hier schon: Bei Satzzeichen müssen wir aufpassen! Wir wollen daraus bekommen:
"Ich", "programmiere", "Java", "Hallo", "schöne", "Java", "Welt"

Also zusammengefasst:
"Ich", "programmiere", "Java", "Hallo", "schöne", "Java", "Welt"
soll durchsucht werden.

Gesucht wird: "Hallo", "", "", "Welt" mit "" steht für ein beliebiges Wort!

Es geht also um das Finden einer Sequenz! Damit die Sequenz überein stimmt, muss ab einer Stelle alle Elemente überein stimmen. Das kann man also einfach machen:
Ich gehe die Sequenz durch vom 0ten Wort bis hin zu (Anzahl-AnzahSuchsequenz)
Wieso diese hintere Grenze: Wenn ich eine Sequenz von 4 Worten suche, dann kann ich aufhören zu suchen, wenn nur noch 3 da sind!

Also fange ich an beim ersten Wort: "Ich" -> Ist das der Anfang der Sequenz? Nein.
"programmiere" -> Nicht Anfang der Sequenz
"Java" -> Nicht Anfang der Sequenz.
"Hallo" -> Ja, Anfang der Sequenz!
--> "schöne" -> Ja, ist in Sequenz (da "" = beliebiges Wort!)
--> "Java" -> Ja, ist in Sequenz (da "" = beliebiges Wort!)
--> "Welt" -> Ja, ist in Sequenz, Sequenz abgeschlossen! Treffer auf der Zeile!

Wir müssen natürlich weitere Testfälle. Was ist mit "Hallo schöne Java Sprache"?
"Hallo" -> Ja, Anfang der Sequenz!
--> "schöne" -> Ja, ist in Sequenz (da "" = beliebiges Wort!)
--> "Java" -> Ja, ist in Sequenz (da "" = beliebiges Wort!)
--> "Sprache" -> Nein, nicht in Sequenz! ==> Hier geht es dann mit der äußeren Schleife weiter:
"schöne" -> Nicht Anfang der Sequenz
...

Das wäre ein Vorgehen das möglich sein könnte. Ist noch etwas oberflächig. Das muss man dann genauer formulieren. Im Code selbst wäre tatsächlich eine Methode a.la. "checkSequence" oder so, die dann prüft: Ist es ein Anfang der Sequenz.
Und da wird dann ein Wort geprüft. Also sowas wie boolean checkWords(String search, String found) was dann prüft:
Ist search leer? Dann passt es (da beliebiges Wort akzeptiert wird!)
Wenn search nicht leer ist, dann werden die Worte verglichen (equals oder equalsIgnoreCase).

So wäre ein mögliches Vorgehen. Einmal etwas erläutert, denn das ist halt das, was man sich etwas hätte erarbeiten müssen. Angefangen von: Was sagt mir die Eingabe? Bis hin zu einem Vorgehen ("Ich prüfe, ob die Sequenz ab demn Punkt startet / vorhanden ist"). Das erste ist Verständnis der Aufgabe. Das zweite ist das Finden eines Lösungsweges. Und da hilft oft Stift und Papier. Ohne geht es auch bei mir nicht. Das wichtigste Werkzeug in Designmeetings und so ist und bleibt das Whiteboard. Man spielt Dinge durch. (Das ist dann natürlich ein anderes Noiveau, aber generell werden Abläufe / Anforderungen verstanden, dokumentiert und dann umgesetzt. Ohne Abläufe / Anforderungen geht es nicht, denn das fließt auch direkt in die Tests ein!)
Vielen Dank! Ich werde erstmal selbst versuchen, das im Code zu formulieren. Bei Fragen melde ich mich.
 
Da nur ein paar Fragen von meiner Seite. Du hast ja als Suchstring:
"Hallo _ _ Welt"

Wo soll das alles reagieren?

"Hallo Du schöne Welt" ist klar -> das ist ein Match
"Hallo Welt" -> Da wurden die _ ignoriert
"Welt Hallo" -> Da stimmt sogar die Reihenfolge nicht!
...

Das ist also relativ deutlich.

Wenn Du alle Wörter des Suchstrings mit allen Wörtern der Zeile vergleichst, dann kann sogar ein einfaches "Hallo" oder "Welt" matchen, also bei
"Was für eine blöde Welt" oder "Ich habe Hallo gesagt" würden dann schon gefunden werden.

Es muss also mehrere Übereinstimmungen geben:
1. Hallo
2. beliebiges Wort
3. beliebiges Wort
4. Welt

Also als erstes musst Du es schaffen, dass Du dies so erkennen kannst. Da gibt es viele Wege. Da Du bereits etwas hattest mit _ entfernen kann man das nutzen:
a) Als erstes ersetzen wir alle Whitespace durch ein Leerzeichen. Also wenn da etwas steht wie "Hallo Welt" dann wird daraus ein "Hallo Welt" ==> replaceAll("\\s+", " ");
b) Dann löschen wir die "" => repalceAll("", "");
c) Dann ein split(" ") und wir bekommen als Resultat bei "Hallo _ _ Welt" ein "Hallo", "", "", "Welt"

Damit hätten wir eine Datenform für unseren Suchstring. Der leere String steht also für ein beliebiges Wort.

Dann ist die Frage, wie wir jetzt Treffer finden. Dazu kann eine Zeile ja irgendwas enthalten. Also z.B. ein:
"Ich programmiere Java. Hallo schöne Java Welt"
Aufteilen in Worte - dabei merken wir hier schon: Bei Satzzeichen müssen wir aufpassen! Wir wollen daraus bekommen:
"Ich", "programmiere", "Java", "Hallo", "schöne", "Java", "Welt"

Also zusammengefasst:
"Ich", "programmiere", "Java", "Hallo", "schöne", "Java", "Welt"
soll durchsucht werden.

Gesucht wird: "Hallo", "", "", "Welt" mit "" steht für ein beliebiges Wort!

Es geht also um das Finden einer Sequenz! Damit die Sequenz überein stimmt, muss ab einer Stelle alle Elemente überein stimmen. Das kann man also einfach machen:
Ich gehe die Sequenz durch vom 0ten Wort bis hin zu (Anzahl-AnzahSuchsequenz)
Wieso diese hintere Grenze: Wenn ich eine Sequenz von 4 Worten suche, dann kann ich aufhören zu suchen, wenn nur noch 3 da sind!

Also fange ich an beim ersten Wort: "Ich" -> Ist das der Anfang der Sequenz? Nein.
"programmiere" -> Nicht Anfang der Sequenz
"Java" -> Nicht Anfang der Sequenz.
"Hallo" -> Ja, Anfang der Sequenz!
--> "schöne" -> Ja, ist in Sequenz (da "" = beliebiges Wort!)
--> "Java" -> Ja, ist in Sequenz (da "" = beliebiges Wort!)
--> "Welt" -> Ja, ist in Sequenz, Sequenz abgeschlossen! Treffer auf der Zeile!

Wir müssen natürlich weitere Testfälle. Was ist mit "Hallo schöne Java Sprache"?
"Hallo" -> Ja, Anfang der Sequenz!
--> "schöne" -> Ja, ist in Sequenz (da "" = beliebiges Wort!)
--> "Java" -> Ja, ist in Sequenz (da "" = beliebiges Wort!)
--> "Sprache" -> Nein, nicht in Sequenz! ==> Hier geht es dann mit der äußeren Schleife weiter:
"schöne" -> Nicht Anfang der Sequenz
...

Das wäre ein Vorgehen das möglich sein könnte. Ist noch etwas oberflächig. Das muss man dann genauer formulieren. Im Code selbst wäre tatsächlich eine Methode a.la. "checkSequence" oder so, die dann prüft: Ist es ein Anfang der Sequenz.
Und da wird dann ein Wort geprüft. Also sowas wie boolean checkWords(String search, String found) was dann prüft:
Ist search leer? Dann passt es (da beliebiges Wort akzeptiert wird!)
Wenn search nicht leer ist, dann werden die Worte verglichen (equals oder equalsIgnoreCase).

So wäre ein mögliches Vorgehen. Einmal etwas erläutert, denn das ist halt das, was man sich etwas hätte erarbeiten müssen. Angefangen von: Was sagt mir die Eingabe? Bis hin zu einem Vorgehen ("Ich prüfe, ob die Sequenz ab demn Punkt startet / vorhanden ist"). Das erste ist Verständnis der Aufgabe. Das zweite ist das Finden eines Lösungsweges. Und da hilft oft Stift und Papier. Ohne geht es auch bei mir nicht. Das wichtigste Werkzeug in Designmeetings und so ist und bleibt das Whiteboard. Man spielt Dinge durch. (Das ist dann natürlich ein anderes Noiveau, aber generell werden Abläufe / Anforderungen verstanden, dokumentiert und dann umgesetzt. Ohne Abläufe / Anforderungen geht es nicht, denn das fließt auch direkt in die Tests ein!)
Oh Gott... Ich wollte gerade anfangen aber habe absolut keine Ahnung wo. Kannst du folgenden Teil vllt noch einmal auf mein spezifisches Problem angewandt erklären/ zeigen?
a) Als erstes ersetzen wir alle Whitespace durch ein Leerzeichen. Also wenn da etwas steht wie "Hallo Welt" dann wird daraus ein "Hallo Welt" ==> replaceAll("\\s+", " ");
b) Dann löschen wir die "" => repalceAll("", "");
c) Dann ein split(" ") und wir bekommen als Resultat bei "Hallo _ _ Welt" ein "Hallo", "", "", "Welt"
 

Zurück
Oben