Regex: Ersetzen Sie eine beliebige Anzahl von Leerzeichen durch dieselbe Anzahl eines anderen Zeichens

1050
AntumDeluge

Was ich versuche zu tun, ist eine Liste, die fast wie ein Inhaltsverzeichnis formatiert ist, und Leerzeichen (einzelne Leerzeichen, keine Tabulatoren) zwischen den linken und rechten Texten durch Punkte ersetzen, wobei nur die beiden äußersten Leerzeichen erhalten bleiben.

Ich möchte also eine Liste wie diese nehmen:

foo url1 foobar url2 foo bar url3 

Und konvertiere es in folgendes:

foo ...... url1 foobar ... url2 foo bar .. url3 

Ich verwende die Eclipse-IDE zum Bearbeiten meines Textes. Ich bin nicht mit den verschiedenen Regex-Engines vertraut, aber ich schätze, dass es entweder Jakarta Regexp oder java.util.regex (die ich in Wikipedia nachgeschlagen habe) verwendet.

Ich kann die Whitespace-Zeichen im Feld Suchen mit " ( +)" erfassen, weiß aber nicht, wie ich sie in die gleiche Anzahl von Punkten im Feld Ersetzen durch konvertieren soll .

Ich habe etwas gegoogelt und bin auf diese Frage gestoßen (wo ich die ( +)Syntax " " gelernt habe ). Es klingt, als könnte es dieselbe sein oder eine ähnliche Frage wie meine. Aber ich habe meine Antwort entweder nicht gefunden oder ich habe die gegebenen Antworten einfach nicht verstanden.

0
Irgendein Leerzeichen oder nur Leerzeichen? Ihr Ausdruck scheint nur über Leerzeichen zu sein. Warum dann nicht einfach den Platz durch einen beliebigen Charakter ersetzen? sticky bit vor 6 Jahren 0
Weil sie keine Leerzeichen im Titel ändern wollen; zB "foo bar" → "foo.bar". Sie möchten auch nicht "foo url" in "foo ........ url" ändern. sie wollen „foo ...... ...... keepingurl“ (das erste und letzte Leerzeichen behalten). Scott vor 6 Jahren 0
@Scott richtig. AntumDeluge vor 6 Jahren 0
Das klingt wie eine zuvor gestellte Frage und wurde möglicherweise bereits hier oder unter [Unix & Linux Stack Exchange] (https://unix.stackexchange.com) beantwortet. Aber ich erinnere mich jetzt nicht an die Antwort. Ich werde später darauf zurückkommen, wenn ich mehr Zeit habe, aber bis dahin schlage ich vor, dass Sie unsere Website ein wenig schwieriger durchsuchen. Hinweis: [SE] hat eine eigene Suchmaschine, aber manchmal erhalten Sie bessere Ergebnisse mit Google und sagen `` `site: superuser.com``` oder` `` site: unix.stackexchange.com```. Scott vor 6 Jahren 0
Ich habe eine kurze Suche durchgeführt (ungefähr 15 Minuten) und konnte keine genauen Übereinstimmungen finden, obwohl [alle Vorkommen am Anfang durch eine übereinstimmende Anzahl von Ersetzungszeichenfolgen ersetzen] (https://unix.stackexchange.com/) q / 433513/23408) und [Zeichen in übereinstimmender Zeile ersetzen] (https://unix.stackexchange.com/q/352502/23408) sind geschlossen. Da niemand Ihre Frage als Duplikat markiert hat und Sie bisher nur eine Antwort erhalten haben, habe ich selbst drei Antworten erfunden (die erste ist einer der in den Fragen, die ich verlinkt habe, sehr ähnlich). Ich hoffe, Sie haben Zugang zu `sed`. Scott vor 6 Jahren 0

2 Antworten auf die Frage

1
Toto

Sie können das mit Notepad ++ tun

  • Ctrl+H
  • Finde was: (?<!\S) (?= )
  • Ersetzen mit: .
  • Aktivieren Sie die Option Wrap around
  • Überprüfen Sie den regulären Ausdruck
  • Replace all

Erläuterung:

(?<! : Start negative lookbehind, make sure we have not \S : a non-space character ) : end lookbehind : a space (?= : start lookahead, make sure we have : a space ) : en lookahead 

Ersatz:

. : a dot 

Ergebnis für gegebenes Beispiel:

foo ...... url1 foobar ... url2 foo bar .. url3 
Sieht interessant aus. Ich habe kein Notepad ++, daher kann ich das nicht testen. Kannst du erklären, warum dies nicht das erste Leerzeichen nach dem Titel ersetzt, was zu `` foo ....... ␣url1`` führt? Scott vor 6 Jahren 0
@Scott: Ich bin mir ziemlich sicher, dass es auch mit SublimeText funktioniert. Ein Leerzeichen wird nur ersetzt, wenn sich vor ihm kein Leerzeichen und danach ein Leerzeichen befindet. Toto vor 6 Jahren 0
Oh ... wenn es ein Leerzeichen danach gibt, und *** kein ** Nicht *** Platz vor. Ich habe das doppelte Negativ vermisst. Könnten Sie nicht einfach einen regulären Look für einen Bereich statt für einen negativen für einen Nicht-Space suchen? Scott vor 6 Jahren 0
@Scott: Nein, wenn ich positives lookbehind (dh. (? <= \ S) `) verwende, ist das Leerzeichen vorher obligatorisch, * ein contrario *` (? Toto vor 6 Jahren 0
Ich verstehe immer noch nicht. :-( ⁠ Scott vor 6 Jahren 0
@Scott: Es ist nicht leicht zu erklären, aber probiere es einfach mit beiden Ausdrücken, dann wird es klar. Toto vor 6 Jahren 0
0
Scott

Die Frage besagt ausdrücklich, dass Titel Leerzeichen enthalten. Zur Sicherheit gehe ich davon aus, dass Titel Punkte (Punkte) enthalten können; zB „Die Geschichte von 3.14159“ oder „Dr. Doolittle Entdeckung “. Meine Antworten gehen davon aus, dass es einen Charakter gibt, der niemals im Inhaltsverzeichnis erscheinen wird. Sie gehen davon aus, dass dies der Fall ist @. Wenn Sie @in Ihrer Tabelle, ersetzen Sie es mit einem gewissen Charakter, der nie erscheint (zB #, ^, _, |, etc.). Wenn Sie wirklich alle ASCII-Zeichen verwenden, müssen Sie möglicherweise eine Zeichenfolge wie <@>.

Drei Möglichkeiten, dies mit zu tun sed:

Schleife:

sed 's/\(.*\)\( \)/\1@\2/; :loop; s/ @/ @./; t loop; s/@//' 
  • s/\(.*\)\( \)/\1@\2/findet das letzte Leerzeichen in der Zeile und fügt ein @davor ein.
  • :loop ist ein Etikett, wie eine Meilenmarke.
  • s/ @/ @./(das heißt s/␣␣@/␣@./, für Mehrdeutigkeit) sagt, wenn vor dem zwei Leerzeichen vorhanden sind @, ersetzen Sie diese durch ␣.(Leerzeichen und Punkt) und verschieben Sie sie @zwischen ihnen.
  • t loopsagt, wenn die obige Ersetzung erfolgreich war, springe zurück zum :loopMarker und wiederhole es. Ansonsten fahren Sie fort mit
  • s/@//, die das entfernt @.

Die foo barZeile in Ihrer Tabelle wird also wie folgt verarbeitet:

Anfangswert: foo bar url3 s / \ (. * \) \ (\) / \ 1 @ \ 2 / foo bar @ url3 s / @ / @. / foo bar @. url3 s / @ / @. / foo bar @ .. url3 s / @ / @. / foo bar @ .. url3 ( Ersetzung schlägt fehl, schleife also nicht) s / @ // foo bar .. url3 Endgültige Ausgabe: foo bar .. url3

Überwältigende Zahlen:

sed 's/\(.*\)\( \)/\1@@@@@@@@@@@@@@@@@@@@\2/; s/ [ @]\/ /; s/@/./g' 
  • s/\(.*\)\( \)/\1@@@@@@@@@@@@@@@@@@@@\2/ ist dem ersten sUnterbefehl in der ersten Lösung sehr ähnlich ; Es findet das letzte Leerzeichen in der Zeile und fügt eine Zeichenfolge von 20 @Zeichen ein. Dies sollte eigentlich eine Zahl sein, die mindestens so groß ist wie die maximale Anzahl von Punkten, die Sie jemals in eine Zeile einfügen müssen. zB 80. Das Verwalten einer Zeichenfolge von 80 @Zeichen wäre umständlich. Möglicherweise möchten Sie dies durch ersetzen
    • s/\(.*\)\( \)/\1<@><@><@><@><@>\2/; s/<@>/@@@@@@@@/g Dadurch wird eine Folge von fünf <@>Sequenzen eingefügt und dann jede von ihnen durch eine Folge von 16 @Zeichen ersetzt, die 5 × 16 = 80 @Zeichen ergibt .
  • s/ [ @]\/ /findet eine Zeichenfolge von 20 aufeinanderfolgenden Zeichen, die entweder ein Leerzeichen oder ein @Leerzeichen sind, und ein Leerzeichen vorangestellt wird, und ersetzt es nur durch das vorangehende Leerzeichen. Ersetzen Sie 20die Nummer aus dem vorherigen Schritt.
  • s/@/./gersetzt jedes verbleibende @durch einen Punkt.

Die fooZeile in Ihrer Tabelle wird also wie folgt verarbeitet:

Initial value: foo url1 s/\(.*\)\( \)/\1@@@@...@@@@\2/ foo @@@@@@@@@@@@@@@@@@@@ url1 s/ [ @]\/ / _[↑↑↑↑↑↑remove↑↑↑↑↑↑] foo @@@@@@ url1 s/@/./g foo ...... url1 

Nutzen Sie den "Hold Space":

sed 's/.*[^ ] /&@/; h; s/ /./g; s/\(\.*\)\./\1 /; x; G; s/@.*@//' 
  • s/.*[^ ] /&@/ist ähnlich zu den vorherigen Befehlen; es findet das Ende des Titels - genauer gesagt, die letzte Stelle, an der ein nicht-leeres Zeichen ein Leerzeichen folgt - und fügt ein @nachher ein.
  • h kopiert die Zeile in den Speicherplatz.
  • s/ /./g ersetzt alle Leerzeichen in der Zeile durch Punkte.
  • s/\(\.*\)\./\1 /ersetzt den letzten Punkt durch ein Leerzeichen. (Dies muss geändert werden, wenn die URL Punkte enthalten kann, was wahrscheinlich wahrscheinlich ist.)
  • x tauscht den Pattern-Space und den Hold-Space aus.
  • GHängt den Haltebereich an den Musterbereich an. Wir haben jetzt im Wesentlichen zwei Exemplare der Zeile.
  • s/@.*@// behält den ersten Teil der ersten Kopie und den zweiten Teil der zweiten Kopie, wobei der Inhalt in der Mitte entfernt wird.
Initial value: foo bar url3  Pattern space Hold space s/.*[^ ] /&@/ foo bar @ url3 h foo bar @ url3 foo bar @ url3 s/ /./g foo.bar.@...url3 foo bar @ url3 s/\(\.*\)\./\1 / foo.bar.@.. url3 foo bar @ url3 x foo bar @ url3 foo.bar.@.. url3 G foo bar @ url3 foo.bar.@.. url3 foo.bar.@.. url3 s/@.*@// foo bar .. url3 foo.bar.@.. url3  Final output: foo bar .. url3