Laden...

Text über Zeilenumbruch hinweg finden

Letzter Beitrag vor 2 Jahren 13 Posts 641 Views
Text über Zeilenumbruch hinweg finden

Hallo,

wie finde ich in einen Text mit Zeilenumbrüchen gemäß einer Vorlage ohne Zeilenumbrüch?
Beispiel:

...emil
und
luise...

möchte ich finden, habe als Suchmuster aber nur ...emil und luise... ohne Zeilenumbrüche.
Das heißt also, der Reguläre Ausdruck muss die Zeilenumbrüche zwischen den Wörtern akzeptieren. Im Regex klappt's. Ich habe das Suchmuster etwas kompliziert aufgebaut: Ich ersetze die Leerzeichem im Suchmuster durch @"([ \r\n]{1,5})" und vor Klammern im Text werden Backslashes eingefügt.
wie gesagt: Im RegexLab klappt's, in meinem Programm nicht. Programmzeile für das Regex-Muster:


string s_patt = Regex.Replace(textBox.Text.ToLower(), " ", @"([ \r\n]{1,5})").Replace("(", "\\(").Replace(")", "\\)");

Kann jemand helfen? Wäre toll!

Der zweite Parameter muss das Pattern sein und nicht das Leerzeichen

Und das Pattern geht auch einfacher: \s+

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

??? hallo Palladin007,
was meinst du mit zweitem Parameter? Und mit '\s' findet der Regex doch nur die Leerzeichen. Die habe ich mir im Muster erspart, dadurchs wird's für mich leichter lesebar.
Was ich in meinem Text nicht gezeigt habe, ist die eigentliche Suche, aber dabei ist nix überraschendes:


Match m = Regex.Match(s_rtbtxt, s_patt, RegexOptions.Singleline);

Wie gesagt, im RegexLab funktioniert es genau so, wie ich's aufgebaut habe.

was meinst du mit zweitem Parameter?

Dass der zweite Parameter das Pattern sein muss.
Regex.Replace(String, String, String)

Und mit '\s' findet der Regex doch nur die Leerzeichen.

Nein.
RegExp \s Metacharacter

Aber ja, dein Pattern geht auch, ich sag nur, dass "\s+" auch reicht.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

Öhm - ja, ich glaube, bezüglich des Patterns habe ich dich verstanden, hab's nämlich gerade mal ausprobiert:


string s_patt = Regex.Replace(tbQntTextSuche.Text.ToLower().Replace("(", "\\(").Replace(")", "\\)"), " ", "([\\s\\r\\n]+)"),

Also erst den Klammer.Replace, dann das Regex. Meintest du das so? Funktioniert nämlich. Deswegen hat das Muster - nur das Muster - im RegexLab funktioniert, da ich mit dem normalen Replace die Klammern wieder verändere. Fiel mir erst jetzt beim Debugging auf.

Tja, und die Sache mit dem '\s' wusste ich nicht. Erstaunlich, dass trotzdem alle meine anderen Regex so gut funktionieren. Ich dachte, ich wäre darin einigermaßen bewandert - Duning-Kruger-Effekt?

Also herzlichen Dank für deine Hilfe! Ich hatte so sehr im Netz gesucht und nur Unpassendes oder Müll gefunden (im_coder.com).

Gehab dich wohl, viel erfolg - MoaByter


string s_patt = Regex.Replace(textBox.Text.ToLower(), @"\s+", " ").Replace("(", "\\(").Replace(")", "\\)");

Kopiert und angepasst aus deiner ursprünglichen Frage.

Und "([\s\r\n]+)" ist immer noch unnötig.
"\r" und "\n" erkennt "\s" von sich aus, dann brauchst Du keine Zeichenklasse mehr und die Gruppe brauchst Du sowieso nicht.
Ergo: \s+

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

Jau, Danke, habe ich umgeschrieben.
allerdings habe ich die Klammer auch noch mit 'nem Regex korrigiert:


string s_patt = Regex.Replace(Regex.Replace(tb_qts.Text.ToLower(), "([()])", "\\" + "$1"), " ", "\\s+");

Vielleicht ginge es ja mit zweimaligem Replace wie in deiner Version schneller ... naja, so sieht's schöner aus.
Das '\s+' hat mir noch Kummer bereitet, ich hatte es zuerst in Klammern und die vergessen 'rauszunehmen, da ging die Geschichte nur mit einem Zeilenumbruch.
Jetzt läuft's aber, der Tipp ist Spitze, werde meine anderen Regex auch überpürfen. Da sind z.T. richtige Ungetüme drin, da ich unterschiedliche Texte bekomme.

Und ich hab's in eine extra Klassse gesetzt ... ... ... und es funktioniert trotzdem! 🙂) Auch wenn's nur 67 Zeilen sind.
So lernt mann, naja: ich, immernoch dazu.

Also sei Bedankt, gehasbe dich wohl, ich muss inne Heia, mich müdet mittlerweile.
Viele Grüße - MoaByter (kommt von Moabit, mein Berliner Bezirk)

Ich verstehe den Sinn von dem Code nicht ...
Zwei mal Replace? Warum?
Wenn Du auch Klammern ersetzen willst, dann mach: [\s()]+

Und das "äußere" Replace ist immer noch falsch herum. Nochmal: Zähle die Parameter der Methode, der zweite Parameter muss das Pattern sein. Du versuchst ein Leerzeichen durch "\s+" zu ersetzen.

Und die Klammern außerhalb der eckigen Klammern sind eine Gruppe, die brauchst Du nur, wenn Du einen bestimmten Teil des Matches erreichen möchtest.

Für mich sieht das ein bisschen so aus, als würdest Du hier durch trial&error durch vor irren wollen.
Bei Regex wirst Du damit nicht glücklich, Du solltest dir dir Grundlagen anschauen.
[Artikel] Regex-Tutorial

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

Scusi, die Antwort hat etwas gedauert, ich hatte heute reichlich anderes zu tun.

Ich verstehe den Sinn von dem Code nicht ...
Zwei mal Replace? Warum?
Wenn Du auch Klammern ersetzen willst, dann mach: [\s()]+

Nein, die Klammern will ich nicht ersetzen, sondern maskieren. Der im WebBrowser selektierte Text dient ja als Regex-Muster und die Klammern würden dabei als Gruppe behandelt.
Ich habe die Regex jetzt einzeln aufgelistet:


    string s_patt = Regex.Replace(tb_qts.Text.ToLower(), "([()])", "\\" + "$1");            // Escape-Zeichen für Klammern
    s_patt = Regex.Replace(s_patt, " +", "\\s+");                                           // Ersetzen der LeerZ. mit \s+
    s_patt = Regex.Replace(s_patt, "\r\n", "");

Und das "äußere" Replace ist immer noch falsch herum. Nochmal: Zähle die Parameter der Methode, der zweite Parameter muss das Pattern sein. Du versuchst ein Leerzeichen durch '\s+' zu ersetzen.

Sind sie nicht. Ich ersetze ganz gezielt die Leerzeichen mit "\s+", denn genau dort befinden sich die Zeilenumbrüche (die ja dank deiner Tipps als Whitespace gelten). Und die ZU stören eben bei der Suche, das Programm findet dann den gesuchten Text nicht, da der eben keine ZU hat bzw. haben sollte (hat er leider manchmal doch, was merkwürdig ist).

Und die Klammern außerhalb der eckigen Klammern sind eine Gruppe, die brauchst Du nur, wenn Du einen bestimmten Teil des Matches erreichen möchtest.


    Regex.Replace(tb_qts.Text.ToLower(), "([()])", "\\" + "$1")

Ja, aus der Gruppe ("([()])") - ist ja nur die Nr.1 - lese ich die gefundene Klammer aus - '(' oder ')' -, die dann mit Maskierung ("\" + "$1") versehen wird: '(' oder eben ')'. Rückbezug oder oder so ähnlich.

Für mich sieht das ein bisschen so aus, als würdest Du hier durch try&error durch vor irren wollen.
Bei Regex wirst Du damit nicht glücklich, Du solltest dir dir Grundlagen anschauen.

>

Ganz so schlimm ist es nicht, aber das RegexLab-Tool hilft nicht immer weiter, manches muss ich da probieren. Tatsächlich funktioniert es jetzt wie gewünscht bis auf eine kleine Kleinigkeit:
Absatzübergreifend findet er den Text auch jetzt nicht. Das dürfte an dem '\s+' liegen, denn in den Absatzumbrüchen stehen Sachen wie '<div> </div>' oder '<br>', eben keine WhiteSpace-Zeichen. Die könnte ich natürlich auch noch 'rausnehmen, aber das wird aufwendiger als nötig.
Regex-Tutorials habe ich einige, und auch gelesen, wenn auch nicht alles. Unter anderem habe ich die Funktionen von '\s' nicht gesehen - das wundert mich schon etwas. Ich weiß aber, dass ich über Regex noch längst nicht alles weiß. Denk' dran: Is'n altes Gehirn, dass sich nicht immer alles schnell merken kann. Ich brauche dazu Praxis, und die erarbeite ich mir gerade - unter anderem mit deiner Hilfe.

Also nochmals viele Dank, wenn ich mal Tipps für das 3-Schichten-Modell brauche, frage ich wieder, werde mich aber erstmal belesen.
einges habe ich jetzt schon ausgelagert, aber es gibt Methoden, die sehr intensiv an der GUI arbeiten, das ginge dann mit subclasses nur mit Invoke, was auf Dauer recht anstrengend ist.
Dennoch werde ich den Artikel gerne lesen.

tschüss bis demnächst mal - MoaByter

Nochmal deutlicher:

Sind sie nicht. Ich ersetze ganz gezielt die Leerzeichen mit "\s+", denn genau dort befinden sich die Zeilenumbrüche (die ja dank deiner Tipps als Whitespace gelten). Und die ZU stören eben bei der Suche, das Programm findet dann den gesuchten Text nicht, da der eben keine ZU hat bzw. haben sollte (hat er leider manchmal doch, was merkwürdig ist).

Ich gebe dem Regex mit dem '\s+' die Anweisung, die ZU in den Wortzwischenräumen zuzulassen bzw. zu ignorieren.
Die Länge des Originaltexts darf ich nicht ändern, da sonst die Indices nicht mehr stimmen.
Und: den Regex an den Originaltext anzupassen fand ich einfacher als umgekehrt.

Der im WebBrowser selektierte Text dient ja als Regex-Muster und die Klammern würden dabei als Gruppe behandelt.

Du möchtest den String für Regex escapen?
In dem Fall: Regex.Escape(String) (Docs)
Das escaped dir alles, was eine gesonderte Bedeutung haben könnte.

Wenn einzelne Zeichen nachträglich doch eine Bedeutung haben sollen, musst Du das manuell machen.
Leerzeichen durch \s+ ersetzen: Simples Replace. Bedenke aber, dass \s mehr erkennt, als nur Leerzeichen.
Die Zeilenumbrüche entfernen: Auch simples Replace, mach das aber am besten mit Environment.NewLine (Docs)

Absatzübergreifend findet er den Text auch jetzt nicht. Das dürfte an dem '\s+' liegen, denn in den Absatzumbrüchen stehen Sachen wie '<div> </div>' oder '<br>', eben keine WhiteSpace-Zeichen.

Für sowas ist Regex eigentlich ideal ^^
https://regex101.com/r/G7YqGz/1
Wie es genau aussehen muss und was Du damit machst, musst Du noch anpassen.

Und da siehst Du auch gleich ein wirklich gutes Regex-Tool.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

Ganz so schlimm ist es nicht, aber das RegexLab-Tool hilft nicht immer weiter, manches muss ich da probieren. Tatsächlich funktioniert es jetzt wie gewünscht bis auf eine kleine Kleinigkeit:
Absatzübergreifend findet er den Text auch jetzt nicht. Das dürfte an dem '\s+' liegen, denn in den Absatzumbrüchen stehen Sachen wie '<div> </div>' oder '<br>', eben keine WhiteSpace-Zeichen. Die könnte ich natürlich auch noch 'rausnehmen, aber das wird aufwendiger als nötig.

Was willst du denn genau machen? Vlt. wäre ja ein HTML (wie AngleSharp) parser besser geeignet

cSharp Projekte : https://github.com/jogibear9988

Du möchtest den String für Regex escapen?
In dem Fall: Regex.Escape(String) (Docs)
Das escaped dir alles, was eine gesonderte Bedeutung haben könnte.
...
Leerzeichen durch \s+ ersetzen: Simples Replace. Bedenke aber, dass \s mehr erkennt, als nur Leerzeichen.
Die Zeilenumbrüche entfernen: Auch simples Replace, mach das aber am besten mit Environment.NewLine (Docs)
...
Für sowas ist Regex eigentlich ideal ^^

>

Wie es genau aussehen muss und was Du damit machst, musst Du noch anpassen.

Und da siehst Du auch gleich ein wirklich gutes Regex-Tool.

Das sind doch mal zwei exzellente Tipps. Regex.Escape kannte ich noch gar nicht, muss also mein Wissen über Regex auf jeden Fall aktualisieren.
Bedankt!
Mittlerweile funktioniert's wie gewünscht, dein Tipp mit "\s" war ideal - eben weil das mehr als Leerzeichen erkennt.
Nun will ich die ganze Sache noch etwas ändern und erweitern, wobei mir das Regex.Escape durchaus helfen könnte.
Nochmals bedankt! 👍 👍

Was willst du denn genau machen? Vlt. wäre ja ein HTML (wie AngleSharp) parser besser geeignet

Das HTML ist nicht das Problem, der ganze Kram liegt nur in HTML vor, deswegen die vielen Tags darin. Die müssen allerdings auch erkennt werden, was gelungen ist. Dennoch oder trotzdem oder wie auch immer Danke für deine Antwort. 🙂