411 Stimmen

Übereinstimmung mit Leerzeichen, aber nicht mit Zeilenumbrüchen

Manchmal möchte ich Leerzeichen abgleichen, aber keine Zeilenumbrüche.

Bislang habe ich mich auf [ \t] . Gibt es einen weniger umständlichen Weg?

554voto

Greg Bacon Punkte 127209

Verwenden Sie ein Doppelnegativ:

/[^\S\r\n]/

Das heißt, not-not-whitespace (das große S ergänzt sich) oder not-carriage-return oder not-newline. Die Verteilung des äußeren not ( d.h. die ergänzende ^ in der Zeichenklasse) mit De-Morgansches Gesetz ist dies gleichbedeutend mit "Leerzeichen, aber kein Wagenrücklauf oder Zeilenumbruch". Einschließlich beider \r et \n im Muster behandelt alle Unix- (LF), klassischen Mac OS- (CR) und DOS-artigen (CR LF) Zeilenumbruch-Konventionen .

Sie brauchen mich nicht beim Wort 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";
}

Sortie :

" "  => match
"\\f" => match
"\\t" => match
"\\r" => no match
"\\n" => no match

Beachten Sie den Ausschluss des vertikalen Tabulators, aber das ist behandelt in Version 5.18 .

Bevor Sie zu sehr protestieren: Die Perl-Dokumentation verwendet die gleiche Technik. Eine Fußnote in der "Whitespace"-Abschnitt von perlrecharclass liest

Vor Perl v5.18, \s nicht mit dem vertikalen Reiter übereinstimmte. [^\S\cK] (undeutlich) mit dem übereinstimmt, was \s traditionell getan.

Le derselbe Abschnitt von perlrecharclass schlägt auch andere Ansätze vor, die den Widerstand der Sprachlehrer gegen das doppelte Negativ nicht verletzen werden.

Außerhalb der Gebietsschema- und Unicode-Regeln oder wenn die /a Schalter in Kraft ist, " \s passt zu [\t\n\f\r ] und, ab Perl v5.18, der vertikale Tabulator, \cK ." Ablegen \r et \n zu verlassen /[\t\f\cK ]/ für passende Leerzeichen, aber nicht für Zeilenumbrüche.

Wenn es sich bei Ihrem Text um Unicode handelt, verwenden Sie einen Code ähnlich dem unten stehenden, um ein Muster aus der Tabelle in den oben erwähnten Abschnitt über die Dokumentation .

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 Trick mit dem Doppelnegativ ist auch für die Zuordnung von Buchstaben nützlich. Denken Sie daran, dass \w entspricht "Wortzeichen", alphabetischen Zeichen et Ziffern und Unterstrich. Wir hässlichen Amerikaner wollen es manchmal als, sagen wir, schreiben,

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

aber eine doppelt-negative Zeichenklasse kann das Gebietsschema respektieren:

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

Die Formulierung "ein Wortzeichen, aber keine Ziffer oder ein Unterstrich" ist ein wenig undurchsichtig. Eine POSIX-Zeichenklasse kommuniziert die Absicht direkter

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

oder mit einer Unicode-Eigenschaft wie szbalint vorgeschlagen

if (/\p{Letter}+/) { ... }

231voto

Borodin Punkte 124906

Die Perl-Versionen 5.10 und später unterstützen zusätzliche vertikale und horizontale Zeichenklassen, \v et \h sowie die allgemeine Leerzeichenklasse \s

Die sauberste Lösung ist die Verwendung des horizontales Leerzeichen Charakterklasse \h . Dies entspricht den Tabulatoren und Leerzeichen des ASCII-Satzes, den nicht umbrechenden Leerzeichen des erweiterten ASCII-Satzes oder einem der folgenden 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

Le Vertikaler Raum Muster \v ist weniger nützlich, passt aber zu diesen Zeichen

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 Whitespace-Zeichen, die mit \v und achtzehn horizontale, die mit \h . \s entspricht dreiundzwanzig Zeichen

Alle Whitespace-Zeichen sind entweder vertikal ou horizontal ohne Überschneidungen, aber sie sind keine richtigen Teilmengen, weil \h entspricht auch U+00A0 NO-BREAK SPACE, und \v passt auch auf U+0085 NEXT LINE, was beides nicht der Fall ist. \s

63voto

Rory O'Kane Punkte 27128

Eine Variante von Gregs Antwort die auch Zeilenumbrüche enthält:

/[^\S\r\n]/

Diese Regex ist sicherer als /[^\S\n]/ ohne \r . Meine Überlegung ist, dass Windows die \r\n für Zeilenumbrüche, und Mac OS 9 verwendete \r . Es ist unwahrscheinlich, dass Sie \r ohne \n Aber wenn Sie es finden, kann es nichts anderes bedeuten als einen Zeilenumbruch. Da also \r einen Zeilenumbruch bedeuten kann, sollten wir auch diesen ausschließen.

19voto

Avinash Raj Punkte 165992

Die unten stehende Regex würde auf Leerzeichen passen, aber nicht auf einen Zeilenumbruch.

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

DEMO

Wenn Sie auch einen Wagenrücklauf hinzufügen möchten, fügen Sie \r mit dem | Operator innerhalb der negativen Vorausschau.

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

DEMO

hinzufügen + nach der nicht erfassenden Gruppe, um einem oder mehreren Leerzeichen zu entsprechen.

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

DEMO

Ich weiß nicht, warum ihr die POSIX-Zeichenklasse nicht erwähnt habt [[:blank:]] die auf alle horizontalen Leerzeichen ( Leerzeichen und Tabulatoren ). Diese POSIX-Chrakterklasse würde auf BRE( Grundlegende REgularausdrücke ), ERE( Erweiterte reguläre Ausdrücke ), PCRE( Perl-kompatible reguläre Ausdrücke ).

DEMO

6voto

Hasan Zafari Punkte 130

Fügen Sie die unten stehende Regex in die Datei finden. Abschnitt und wählen Sie Regulärer Ausdruck aus dem "Suchmodus":

[^\S\r\n]+

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X