Übereinstimmende Leerzeichen, aber keine Zeilenumbrüche

276

Ich möchte manchmal Leerzeichen, aber keine Zeilenumbrüche verwenden.

Bisher habe ich darauf zurückgegriffen [ \t] . Gibt es einen weniger unangenehmen Weg?

JoelFan
quelle
4
Übrigens sind diese Zeichen auch "Leerzeichen" : [\r\f].
Eugene Yarmash
2
@ Eugeney macht noch jemand Formular-Feeds? (\ f's)
Aran Mulholland
1
@AranMulholland: Jeder, der einen zeichenorientierten Drucker hat. Die meisten Drucker haben einen Zeichenmodus sowie PostScript oder wie auch immer die Hewlett Packard-Oberfläche heißt. Um eine Seite zu werfen, senden Sie einen Formular-Feed.
Borodin
1
@Borodin Hewlett Packard's heißt PCL (Printer Control Language).
CB_Ron

Antworten:

182

Perl - Versionen 5.10 und höher unterstützen Tochter vertikale und horizontale Zeichenklassen, \vund \hsowie die allgemeine Leerzeichenklasse\s

Die sauberste Lösung besteht darin, die horizontale Leerzeichenzeichenklasse zu verwenden \h. Dies entspricht der Registerkarte und dem Leerzeichen aus dem ASCII-Satz, dem nicht unterbrechenden Leerzeichen aus dem erweiterten ASCII-Satz oder einem dieser Unicode-Zeichen

U+0009 CHARACTER TABULATION
U+0020 SPACE
U+00A0 NO-BREAK SPACE (not matched by \s)

U+1680 OGHAM SPACE MARK
U+2000 EN QUAD
U+2001 EM QUAD
U+2002 EN SPACE
U+2003 EM SPACE
U+2004 THREE-PER-EM SPACE
U+2005 FOUR-PER-EM SPACE
U+2006 SIX-PER-EM SPACE
U+2007 FIGURE SPACE
U+2008 PUNCTUATION SPACE
U+2009 THIN SPACE
U+200A HAIR SPACE
U+202F NARROW NO-BREAK SPACE
U+205F MEDIUM MATHEMATICAL SPACE
U+3000 IDEOGRAPHIC SPACE

Das vertikale Raummuster \vist weniger nützlich, stimmt jedoch mit diesen Zeichen überein

U+000A LINE FEED
U+000B LINE TABULATION
U+000C FORM FEED
U+000D CARRIAGE RETURN
U+0085 NEXT LINE (not matched by \s)

U+2028 LINE SEPARATOR
U+2029 PARAGRAPH SEPARATOR

Es gibt sieben vertikale Leerzeichen, die übereinstimmen, \vund achtzehn horizontale Leerzeichen , die übereinstimmen \h. \sentspricht dreiundzwanzig Zeichen

Alle Leerzeichen sind entweder vertikal oder horizontal ohne Überlappung, aber sie sind keine richtigen Teilmengen, da sie \hauch mit U + 00A0 NO-BREAK SPACE und \vU + 0085 NEXT LINE übereinstimmen, von denen keine übereinstimmen\s

Borodin
quelle
7
\hfunktioniert nur in den unterstützten Sprachen PCRE.
Avinash Raj
14
@AvinashRaj: Diese Frage bezieht sich auf Perl, das PCRE
Borodin
2
@ AvashashRaj: Außer das [[:blank:]]passt nicht No-Break Space -  oder"\xA0"
Borodin
6
\hIch möchte erwähnen, dass dies perfekt für meinen Anwendungsfall funktioniert hat, bei dem in Notepad ++ ein oder mehrere zusammenhängende Leerzeichen ohne neue Zeilen gefunden / ersetzt wurden. Sonst (einfach) hat nichts funktioniert.
Squidbe
8
Was Perl \hetwas unüblich macht, ist seine Einbeziehung von MONGOLIAN VOWEL SEPARATOR. Unicode betrachtet es nicht als Leerzeichen. Aus diesem Grund unterscheidet sich Perl \hvon POSIX blank( [[:blank:]]in Perl, \p{Blank}in Java) und Java 8 \h. Zugegeben, es ist ein Randfall.
Aleksandr Dubinsky
360

Verwenden Sie ein doppeltes Negativ:

/[^\S\r\n]/

Das heißt, kein Nicht-Leerzeichen (das Kapital S ergänzt) oder kein Wagenrücklauf oder kein Zeilenumbruch. Wenn Sie das äußere Nicht ( dh die Ergänzung ^in der Zeichenklasse) mit De Morgans Gesetz verteilen, entspricht dies „Leerzeichen, aber nicht Wagenrücklauf oder Zeilenumbruch“. Wenn Sie beide \rund \ndas Muster korrekt einschließen , werden alle Unline- (LF), klassischen Mac OS- (CR) und DOS- ish- (CR LF) Newline-Konventionen korrekt behandelt .

Ich brauche nicht mein Wort dafür zu nehmen:

#! /usr/bin/env perl

use strict;
use warnings;

use 5.005;  # for qr//

my $ws_not_crlf = qr/[^\S\r\n]/;

for (' ', '\f', '\t', '\r', '\n') {
  my $qq = qq["$_"];
  printf "%-4s => %s\n", $qq,
    (eval $qq) =~ $ws_not_crlf ? "match" : "no match";
}

Ausgabe:

"" => Übereinstimmung
"\ f" => Übereinstimmung
"\ t" => Übereinstimmung
"\ r" => keine Übereinstimmung
"\ n" => keine Übereinstimmung

Beachten Sie den Ausschluss der vertikalen Registerkarte, dies wird jedoch in Version 5.18 behandelt .

Bevor zu heftige Einwände erhoben werden, wird in der Perl-Dokumentation dieselbe Technik verwendet. Eine Fußnote im Abschnitt "Leerzeichen" der Perlrecharklasse lautet

Vor Perl v5.18 \sstimmte die vertikale Registerkarte nicht überein. [^\S\cK](dunkel) entspricht dem, was \straditionell getan wurde.

Der gleiche Abschnitt der Perlrecharklasse schlägt auch andere Ansätze vor, die den Widerstand der Sprachlehrer gegen Doppel-Negative nicht verletzen .

Außerhalb der Gebietsschema- und Unicode-Regeln oder wenn der /aSchalter aktiv ist, " \sstimmt überein [\t\n\f\r ]und ab Perl v5.18 mit der vertikalen Registerkarte \cK". Verwerfen \rund \nverlassen, /[\t\f\cK ]/um passende Leerzeichen, aber keine Zeilenumbrüche zu erhalten.

Wenn Ihr Text Unicode ist, verwenden Sie Code ähnlich dem folgenden Unter, um ein Muster aus der Tabelle im oben genannten Dokumentationsabschnitt zu erstellen .

sub ws_not_nl {
  local($_) = <<'EOTable';
0x0009        CHARACTER TABULATION   h s
0x000a              LINE FEED (LF)    vs
0x000b             LINE TABULATION    vs  [1]
0x000c              FORM FEED (FF)    vs
0x000d        CARRIAGE RETURN (CR)    vs
0x0020                       SPACE   h s
0x0085             NEXT LINE (NEL)    vs  [2]
0x00a0              NO-BREAK SPACE   h s  [2]
0x1680            OGHAM SPACE MARK   h s
0x2000                     EN QUAD   h s
0x2001                     EM QUAD   h s
0x2002                    EN SPACE   h s
0x2003                    EM SPACE   h s
0x2004          THREE-PER-EM SPACE   h s
0x2005           FOUR-PER-EM SPACE   h s
0x2006            SIX-PER-EM SPACE   h s
0x2007                FIGURE SPACE   h s
0x2008           PUNCTUATION SPACE   h s
0x2009                  THIN SPACE   h s
0x200a                  HAIR SPACE   h s
0x2028              LINE SEPARATOR    vs
0x2029         PARAGRAPH SEPARATOR    vs
0x202f       NARROW NO-BREAK SPACE   h s
0x205f   MEDIUM MATHEMATICAL SPACE   h s
0x3000           IDEOGRAPHIC SPACE   h s
EOTable

  my $class;
  while (/^0x([0-9a-f]{4})\s+([A-Z\s]+)/mg) {
    my($hex,$name) = ($1,$2);
    next if $name =~ /\b(?:CR|NL|NEL|SEPARATOR)\b/;
    $class .= "\\N{U+$hex}";
  }

  qr/[$class]/u;
}

Andere Anwendungen

Der doppelt negative Trick ist auch praktisch, um alphabetische Zeichen abzugleichen. Denken Sie daran, dass dies \wmit „Wortzeichen“, alphabetischen Zeichen sowie Ziffern und Unterstrichen übereinstimmt . Wir hässlichen Amerikaner wollen es manchmal so schreiben, als ob

if (/[A-Za-z]+/) { ... }

Eine doppelt negative Zeichenklasse kann jedoch das Gebietsschema respektieren:

if (/[^\W\d_]+/) { ... }

Auf diese Weise „ein Wortzeichen, aber keine Ziffer oder Unterstrich“ auszudrücken, ist etwas undurchsichtig. Eine POSIX-Zeichenklasse kommuniziert die Absicht direkter

if (/[[:alpha:]]+/) { ... }

oder mit einer Unicode-Eigenschaft, wie von szbalint vorgeschlagen

if (/\p{Letter}+/) { ... }
Greg Bacon
quelle
4
Clever, aber das Verhalten ist sehr überraschend, und ich sehe nicht, wie es weniger umständlich ist.
Qwertie
7
@ Qwertie: Was ist überraschend? Weniger umständlich als was?
Ysth
9
Hervorragend schrecklich.
9
Das ist sehr gut. Wie gewünscht stimmen Sie mit Leerzeichen überein (nicht nur mit einigen Leerzeichen), und Sie schließen das Zeilenvorschubzeichen aus. Ihre Lösung befasst sich nicht mit der Frage: "Welche Leerzeichen gibt es?", Wie es nicht sein sollte. Genau das habe ich gesucht. (Wie @Rory erwähnte, ein ‚Newline‘ kann auch \r, zB unter Windows, so denken Sie daran auch diejenigen , die aus dem Spiel gewählte Art: /[^\S\r\n]/)
Timo
1
Dies wird sicherlich den Bedürfnissen des OP und praktisch aller anderen, die diese Frage suchen, gerecht (jedenfalls englischsprachig). Aber es ist immer noch eine schlechte Antwort. Es gibt einfach keine Entschuldigung für die Verwendung dieser Lösung, wenn sie \hverfügbar ist.
Alan Moore
49

Eine Variation von Gregs Antwort , die auch Wagenrückläufe enthält:

/[^\S\r\n]/

Diese Regex ist sicherer als /[^\S\n]/mit Nr \r. Meine Argumentation ist, dass Windows \r\nfür Zeilenumbrüche und Mac OS 9 verwendet \r. Sie sind wahrscheinlich nicht finden , \rohne \nheute, aber wenn Sie es finden, es könnte nicht gemein alles andere als eine neue Zeile. Da \rdies eine neue Zeile bedeuten kann, sollten wir sie auch ausschließen.

Rory O'Kane
quelle
1
+1 Gregs Lösung hat meinen Text beschädigt, deine hat gut funktioniert.
Timo Huovinen
Sie werden überrascht sein, wie viele Programme noch "\ r" für Zeilenenden verwenden. Manchmal habe ich eine Weile gebraucht, um herauszufinden, dass mein Problem darin bestand, dass die Datei diese verwendete. Oder dass es die MacRoman-Zeichenkodierung verwendet hat ...
mivk
2
sieht so aus, als hätte @Greg es zuerst "falsch" geändert und dich nicht gutgeschrieben. Deshalb stimme ich hier ab.
Andre Elrico
14

Der unten stehende reguläre Ausdruck würde mit Leerzeichen übereinstimmen, jedoch nicht mit einem neuen Linienzeichen.

(?:(?!\n)\s)

DEMO

Wenn Sie auch Wagenrücklauf hinzufügen möchten, fügen Sie \rmit dem |Operator innerhalb des negativen Lookaheads hinzu.

(?:(?![\n\r])\s)

DEMO

Fügen Sie +nach der Nicht-Erfassungsgruppe eines oder mehr Leerräume passen.

(?:(?![\n\r])\s)+

DEMO

Ich weiß nicht, warum Sie die POSIX-Zeichenklasse, [[:blank:]]die mit horizontalen Leerzeichen ( Leerzeichen und Tabulatoren ) übereinstimmt, nicht erwähnt haben . Diese POSIX-Chracter-Klasse funktioniert mit BRE ( Basic REgular Expressions ), ERE ( Extended Regular Expression ) und PCRE ( Perl Compatible Regular Expression ).

DEMO

Avinash Raj
quelle
Dies ist die beste Lösung!
Loretoparisi
13

Was Sie suchen, ist die POSIX- blankZeichenklasse. In Perl wird darauf verwiesen als:

[[:blank:]]

in Java (nicht vergessen zu aktivieren UNICODE_CHARACTER_CLASS):

\p{Blank}

Im Vergleich zu ähnlichen \hwird POSIX blankvon einigen weiteren Regex-Engines unterstützt ( Referenz ). Ein Hauptvorteil besteht darin, dass seine Definition in Anhang C festgelegt ist: Kompatibilitätseigenschaften von regulären Unicode-Ausdrücken und Standard für alle Regex-Varianten, die Unicode unterstützen. (In Perl wird beispielsweise \hzusätzlich das eingeschlossen MONGOLIAN VOWEL SEPARATOR.) Ein Argument dafür \hist jedoch, dass immer Unicode-Zeichen erkannt werden (auch wenn sich die Engines nicht darüber einig sind), während POSIX-Zeichenklassen häufig standardmäßig ASCII sind -nur (wie in Java).

Das Problem ist jedoch, dass selbst das Festhalten an Unicode das Problem nicht zu 100% löst. Berücksichtigen Sie die folgenden Zeichen, die in Unicode nicht als Leerzeichen gelten:

Der oben erwähnte mongolische Vokaltrenner ist aus wahrscheinlich guten Gründen nicht enthalten. Es kommt zusammen mit 200C und 200D in Wörtern (AFAIK) vor und verstößt daher gegen die Grundregel, die alle anderen Leerzeichen befolgen: Sie können damit tokenisieren. Sie sind eher Modifikatoren. Allerdings ZERO WIDTH SPACE, WORD JOINERund ZERO WIDTH NON-BREAKING SPACE(wenn es als etwas anderes als eine Byte-Reihenfolge - Marke verwendet wird ) paßt die Leerzeichen Regel in meinem Buch. Daher füge ich sie in meine horizontale Leerzeichen-Zeichenklasse ein.

In Java:

static public final String HORIZONTAL_WHITESPACE = "[\\p{Blank}\\u200B\\u2060\\uFFEF]"
Aleksandr Dubinsky
quelle
Sie müssen der Java-Kompilierung die entsprechenden Regexp-Kompilierungsflags hinzufügen und Java 7 oder höher ausführen. Auf jeden Fall ging es bei der Frage überhaupt nicht um Java oder PCRE, daher ist dies alles unerheblich.
Tchrist
@tchrist Vielen Dank für den Hinweis. Ich werde meine Antwort aktualisieren. Ich bin jedoch nicht der Meinung, dass meine Antwort irrelevant ist. Was unerheblich ist, ist das perlTag in der ursprünglichen Frage.
Aleksandr Dubinsky
1
@AleksandrDubinsky, \ p {Blank} wird in JavaScript nicht unterstützt, also definitiv nicht "Standard für alle Regex-Aromen" -1
Valentin Vasilyev
Am informativsten. Ich finde es beunruhigend zu wissen, dass es keine allgemeine und vollständige "horizontale Leerzeichen" -Kurzzeichenklasse gibt und dass solche Horrorarten [\p{Blank}\u200b\u180e]erforderlich sind. Zugegeben, es ist sinnvoll, dass ein Vokaltrennzeichen nicht als Leerzeichen betrachtet wird, aber warum Leerzeichen mit der Breite Null nicht in Klassen wie \sund enthalten sind \p{Blank}, schlägt mich.
Timo
Follow-up: Ich habe gelesen, dass beide als "grenzenneutral" gelten, obwohl das nicht erklärt, warum .
Timo
-4

m/ /gGeben Sie einfach Platz / /, und es wird funktionieren. Oder verwenden Sie \S- es ersetzt alle Sonderzeichen wie Tabulatoren, Zeilenumbrüche, Leerzeichen usw.

saiprathapreddy.obula
quelle