Suche nach String mit unbekannten characters

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?

Das waren ja schon Aufrufe auf dem String. Also Dein Code mal angepasst so dass nur die erste Zeile der Datei ausgewertet wird:

Java:
public static String[] getTokenFromFile(String filename) {
    try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
        String line = br.readLine();
        if (line == null) return new String[0];
        return line
            .replace("\\s+", " ")
            .replace("_", "")
            .split(" ");
    }
    catch (IOException ex) {
        ex.printStackTrace();
        return new String[0];
    }
}

ah nvm hab zumindest den ersten Teil...
Zu spät 🙂
 
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!)
Kannst du mal zeigen, wie so etwas in der art, auf dieses Problem bezogen funktioniert:
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).
Das ist mein derzeitiger Code:
Finden der Störung + neue Formatierung
Java:
public class StoerungSearch {

    public static String[] lineSplit = null;
    public static int lengthStoerung;

    public static void stoerung0() throws IOException {

        try (BufferedReader br = new BufferedReader(new FileReader("src/defaultpackage/stoerung0.txt"))) {
            for (String line; (line = br.readLine()) != null;) {
                line = line.replaceAll("\\s+", "");
                line = line.replaceAll("", "");
                String re = line.replaceAll("_", "");
                lineSplit = re.split(" +");   
                lengthStoerung = re.length();
            }
        }
    }
unvollständiger / falscher Ansatz für die Suche:
Code:
public void parseFile0(String fileName) throws FileNotFoundException, IOException {
        StoerungSearch.stoerung0();
        String line = null;
        String output = "";
        try {
            int x = 0;
            Scanner scan = new Scanner(new File(fileName));
            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;

                        }
                    }
                }
            }
//weiterer aber hierfür unwichtiger code
 
Zum Verständnis:
  • Was willst Du mit Zeile 11 des StoerungSearch Codes? Der leere String soll durch den leeren String ersetzt werden?
  • Was für eine Bedeutung sollen die "_" haben? Du ignorierst Die komplett. Sollten das keine Platzhalter für beliebige Wörter sein?

Und dann Teil Code auf in Methoden, damit Du diesen auch testen kannst. Versuch auch einmal, Klassen zu bilden. So kann es eine Klasse Sequence geben. Diese kapselt dann das String Array. Das Auswerten einer Zeile um eine Sequence zu bekommen, kann dann eine Factory Methode sein. Und da kann man dann gezielt Code implementieren.

Das wäre dann im ersten Schritt einfach etwas wie:
Java:
package de.kneitzel;

import java.util.Arrays;

public class Sequence {
    private String[] wordSequence;
    
    Sequence(String... words) {
        wordSequence = words;
    }

    public static Sequence createSearchSequence(String line) {
        return new Sequence(line
                .replaceAll("\\s+", " ")
                .replaceAll("_", "")
                .split(" ")
        );
    }

    public static Sequence createContentSequence(String line ) {
        return new Sequence(line
                .replaceAll("[,.:;!_-]", " ")
                .replaceAll("\\s+", " ")
                .split(" ")
        );
    }
}

Und da kann man dann weitere Funktionalität bauen. Eine erste wäre dann etwas wie contains. Da muss man dann jetzt aber beschreiben, was das bedeuten würde. Das könnte also bedeuten, dass eine Sequence ohne Unterbrechung vorhanden sein muss.

Das wäre dann die Methode contains. Was macht diese?
  • sie probiert alle Indices, die in Frage kommen, durch, ob an der Stelle die gesuchte Sequence zu finden ist. Ist dies der Fall, dann wird true zurück gegeben
  • Wenn an allen Indices nichts gefunden wurde, dann wird false zurück gegeben

Java:
    public boolean contains(Sequence searchSequence) {
        for (int sourceIndex = 0; sourceIndex < getLength() - searchSequence.getLength(); sourceIndex++) {
            if (isSearchSequenceAt(sourceIndex, searchSequence)) return true;
        }
        return false;
    }

Also brauchen wir jetzt die Methode, die prüft, ob die gesuchte Sequence an einem Index zu finden ist.
Dazu geht man einfach die Suchsequenz durch und prüft, ob die Wörter alle passen (und geht dabei beim source Index auch immer weiter!)
Sobald ein Wort nicht passt, wissen wir: Die sequence ist nicht an der Stelle zu finden.
Konnten alle Suchwörter verifiziert werden, dann wird true zurück gegeben.
Und ein Wort ist nicht passend, wenn das Suchwort vorhanden ist (Länge > 0) und ein equalsIgnoreCase nicht true zurück gibt.

Das wäre dann in Code sowas:
Java:
    private boolean isSearchSequenceAt(int startIndex, Sequence searchSequence) {
        int sourceIndex = startIndex;
        for (int searchIndex=0; searchIndex< searchSequence.getLength(); searchIndex++,sourceIndex++) {
            String searchWord = searchSequence.getWord(searchIndex);
            String sourceWord = getWord(sourceIndex);
            if (searchWord.length() > 0 && !searchWord.equalsIgnoreCase(sourceWord)) return false;
        }
        return true;
    }

Dann natürlich noch der übliche Kleinkram - so brauchte ich zwei Getter:
Java:
    public String getWord(int sourceIndex) {
        return wordSequence[sourceIndex];
    }

    public int getLength() {;
        return wordSequence.length;
    }

Da fehlen natürlich jeweils noch ein paar Validierungen von Parametern, aber das ist bei der Kern-Funktionalität erst einmal egal.

Der Code ist ungetestet. Da jetzt gleich Fussball kommt, kann ich die gerade nicht schreiben. Hat auch so jetzt gerade so geklappt.

Aber ich hoffe, die Beschreibung, wie ich sowas angehen würde, war halbwegs verständlich.
 
Wenn du jetzt nicht antworten kannst, dann ist das in Ordnung. Dennoch Blicke ich noch nicht wirklich durch, was das angeht. Das soll jetzt wirklich nicht frech klingen, aber kannst du versuchen diesen Teil in meinen Code zu implementieren? Vielleicht erschließt sich da bei mir alles. Denn nachdem ich auch im Internet nachgeschaut habe und es selbst probiert habe, bekam ich es nicht hin. Trotzdem möchte ich die Aufgabe unbedingt fertigstellen.
 

Zurück
Oben