Heinz: regulärer Ausdruck

Hallo!

ich möchte gerne folgendes in einer HTML-Datei finden

<h1>
<h1 style="...">

aktuell ist mein regulärer Ausdruck wie folgt:
grep -n "<[a-zA-Z0-9]+>" test.txt

damit wird "<h1>" gefunden, jedoch nicht "<h1 style="...">"

wenn ich den regulären Ausdruck wie folgt abändere
grep -n "<.*+>" test.txt
findet er leider auch "< xyz >"

Wie müßte ich den regulären Ausdruck abändern, damit er "< irgendetwas bis zum nächsten >" findet?

Heinz

  1. Wie müßte ich den regulären Ausdruck abändern, damit er "< irgendetwas bis zum nächsten >" findet?

    <[^>]+>

    (Zeichenklasse mit [], darin verneint mit ^ ein >, also alles außer >, von dieser Zeichenklasse eins oder mehrere Zeichen)

    nicht zu verwechseln mit

    <°(((><

    Mathias

    1. Guten Abend,

      Wie müßte ich den regulären Ausdruck abändern, damit er "&lt; irgendetwas bis zum nächsten &gt;" findet?

      <[^>]+>

      (Zeichenklasse mit [], darin verneint mit ^ ein >, also alles außer >, von dieser Zeichenklasse eins oder mehrere Zeichen)

      Beachte auch, dass hier grep benutzt wird, also die Ausführung in einer Shell zu vermuten ist. Da müssen die Zeichen < und > auch escaped werden, weil sie sonst von der Shell gefressen werden.

      Gesundheit!
      Dr. Bit

    2. <[^>]+>

      so ganz funktioniert der Ausdruck leider nicht.

      cat test.txt
      <b>
      <h1>
      &lt;h1&gt;
      &lt;b&gt;
      &lt;h1 style=&quot;&quot;&gt;
      &lt; test &gt;
      <b style="...">test</b>
      </b>
      h1 < h2 h2 > h3

      grep "&lt;[^>]+&gt;" test.txt
      &lt;h1&gt;
      &lt;b&gt;
      &lt;h1 style=&quot;&quot;&gt;
      &lt; test &gt;

      "&lt; test &gt;" sollte er nicht finden

      Wie schliesse ich "&gt" aus? [^>] ist leider nicht ganz richtig.

      Wie kann/muss ich den regulären Ausdruck erweitern, dass nach &lt; und vor &gt; kein Leerzeichen stehen darf?

      der nachfolgende Ausdruck findet leider zu wenig
      grep "&lt;[^\ ][^>]+[^\ ]&gt;" test.txt
      &lt;h1 style=&quot;&quot;&gt;

      Heinz

      1. der nachfolgende Ausdruck findet leider zu wenig
        grep "&lt;[^\ ][^>]+[^\ ]&gt;" test.txt

        Klar, weil mindestens drei Zeichen zwischen < und > stehen müssen.

        Wenn du es genauer haben willst, dann musst du die Start-Tag-Syntax genauer mit einem regulären Ausdruck (vereinfacht) abbilden. Ein Start-Tag besteht aus einem <, darauf folgen einige Buchstaben und ggf. Zahlen. Dann ist der Tag zuende oder es kommen noch Attribute. Die fangen mit Whitespace an, dann kommt der Attributname aus Buchstaben, dann das Gleichheitsszeichen, dann der Attributwert eingefasst in " oder '. Dieses Schema kann beliebig häufig. Schließlich steht am Ende >.

        Könnte z.B. so aussehen:

        <[a-z\d]+(\s+[a-z]+=("[^"]*"|'[^']*'))*>

        Das nur als Beispiel, nicht als Fertiglösung. Eine solche kannst du mit den Hinweisen aber erarbeiten.

        Mathias

        1. @@molily:

          Du hast ’ne ganze Menge Nichts vergessen:

          Dann ist der Tag zuende oder es kommen noch

          optionaler Whitespace oder

          Attribute. Die fangen mit Whitespace an, dann kommt der Attributname aus Buchstaben, dann

          optionaler Whitespace, dann

          das Gleichheitsszeichen, dann

          optionaler Whitespace, dann

          der Attributwert eingefasst in " oder '. Dieses Schema kann beliebig häufig. Schließlich steht am Ende

          optionaler Whitespace und

          .

          Live long and prosper,
          Gunnar

          --
          Erwebsregel 208: Manchmal ist das einzige, was gefährlicher als eine Frage ist, eine Antwort.
          1. Als ich meinen Beitrag schrieb, wusste ich genau, dass jemand namens Gunnar Bittersmann mich missversteht und darauf anspringen wird. Und ja: Ich bin mir völlig dessen bewusst, was du schreibst. Aber: Ich habe das absichtlich weggelassen. Warum, ergibt sich aus keinem technischen Erfordernis, sondern aus der Sprechsituation hier im Forum hier im Thread. Und ich würde es wieder tun. Ich habe nicht umsonst angemerkt, dass ich nicht die offizielle mögliche SGML-Syntax wiedergebe, sondern eine vereinfachte Variante. Weil es mir überhaupt nicht darum ging, eine Fertiglösung zu bieten oder die mögliche SGML-Syntax zu erklären, sondern einen Anstoß zu geben. Dass die Beispiel-RegExp »nur« auf einen Großteil des HTMLs zutrifft, es vom Einsatzzweck abhängt, ob sie ausreichend ist, und es noch viel genauer, flexibler und damit komplizierter geht, hätte ich durchaus noch einmal betonen können. Aber wenn der Fragesteller diesen regulären Ausdruck verstanden hat und damit selbstständig weiterarbeiten kann, und darum ging es mir vor allem, kann ich ihn immer noch vor komplexere Aufgaben stellen. Insofern halte ich dein Posting für wenig hilfreich und der Situation unangemessen.

            Mathias

        2. Hi!

          <[a-z\d]+(\s+[a-z]+=("[^"]*"|'[^']*'))*>

          er kann so nicht aussehen, da du <> und " verwendest
          ich muss dafür jeweils folgende Zeichen verwenden

          < => &lt;

          => &gt;

          " => &quot;

          [^"] <--- wie muss ich das schreiben, damit "nicht &qout;" da drin steht?

          [^&quot;] bedeutet doch, dass nicht die &, q, u, o, t und ; vorkommen dürfen

          Ich scheiter gerade an dieser Negation.

          Heinz

          1. [^"] <--- wie muss ich das schreiben, damit "nicht &qout;" da drin steht?

            Das geht nicht mit negativen Zeichenklassen. Da kannst du nur .* für beliebig viele Zeichen verwenden und ein ? dahinter, damit der Teil nicht »greedy« ist, also nur soviele Zeichen umspannt, bis ein &quot; folgt: &quot;.*?&quot;
            Solche Konstruktionen waren bei mir aber immer trotz ungreedy-Flag unzuverlässig... vielleicht kennt jemand eine bessere Möglichkeit.

            Mathias

            1. Hi!

              [^"] <--- wie muss ich das schreiben, damit "nicht &qout;" da drin steht?

              Das geht nicht mit negativen Zeichenklassen. Da kannst du nur .* für beliebig viele Zeichen verwenden und ein ? dahinter, damit der Teil nicht »greedy« ist, also nur soviele Zeichen umspannt, bis ein &quot; folgt: &quot;.*?&quot;
              Solche Konstruktionen waren bei mir aber immer trotz ungreedy-Flag unzuverlässig... vielleicht kennt jemand eine bessere Möglichkeit.

              mein Ausdruck sieht jetzt wie folgt aus
              grep -wE "&lt;/?[a-zA-Z]+[a-zA-Z0-9]*.*?&gt;" test.txt
              ob ich damit alles abgedeckt habe?

              Warum findet
              grep -wE "&lt;/?[:alpha:]+[:alnum:]*.*?&gt;" test.txt
              folgende Zeile nicht "&lt;b&gt;"?

              Heinz

              1. Hi!

                Warum findet
                grep -wE "&lt;/?[:alpha:]+[:alnum:]*.*?&gt;" test.txt
                folgende Zeile nicht "&lt;b&gt;"?

                es wäre super, wenn mir noch jemand ein Tipp geben könnte, warum diese Zeile nicht "&lt;b&gt;" findet.

                Danke!

                Heinz

                1. @@Heinz:

                  grep -wE "&lt;/?[:alpha:]+[:alnum:]*.*?&gt;" test.txt

                  Was soll '.*?' bewirken?

                  Live long and prosper,
                  Gunnar

                  --
                  Erwebsregel 208: Manchmal ist das einzige, was gefährlicher als eine Frage ist, eine Antwort.
                  1. Hi!

                    grep -wE "&lt;/?[:alpha:]+[:alnum:]*.*?&gt;" test.txt

                    Was soll '.*?' bewirken?

                    jedes beliebe Zeichen beliebig oft aber Nongreedy Matching

                    Heinz

                    1. Was soll '.*?' bewirken?

                      jedes beliebe Zeichen beliebig oft aber Nongreedy Matching

                      Das widerspricht sich.

                      Struppi.

                      1. Was soll '.*?' bewirken?

                        jedes beliebe Zeichen beliebig oft aber Nongreedy Matching

                        Das widerspricht sich.

                        Wieso das?

                        Mathias

                        1. Was soll '.*?' bewirken?

                          jedes beliebe Zeichen beliebig oft aber Nongreedy Matching

                          Das widerspricht sich.

                          Wieso das?

                          Ein beliebiges Zeichen soll so oft wie möglich gefunden werden, aber nicht gierig, was soll das nicht gierig bewirken?

                          Struppi.

                          1. Ja ok, ich seh's ein.

                            Struppi.

                          2. Ein beliebiges Zeichen soll so oft wie möglich gefunden werden, aber nicht gierig, was soll das nicht gierig bewirken?

                            Macht natürlich nur Sinn, wenn dahinter der Reguläre Ausdruck noch weitergeht, sodass .*? nur soweit reicht, bis das dahinter das erste Mal matcht.

                            "bla ende bla ende".match(/.*ende/) == "bla ende bla ende" // greedy
                            "bla ende bla ende".match(/.*?ende/) == "bla ende" // non-greedy

                            Mathias

  2. Hi!

    kannst du mir sagen, warum

    grep -wE "&lt;/?[:alpha:]+[:alnum:]*.*?&gt;" test.txt

    "&lt;b&gt;" nicht erkennt?

    grep -wE "&lt;/?[a-zA-Z]+[a-zA-Z0-9]*.*?&gt;" test.txt

    erkennt ihn.

    [:alnum:] ist doch das gleiche wie [a-zA-Z0-9], oder?

    Heinz