Dopasuj białe znaki, ale nie nowe wiersze

277

Czasami chcę dopasować białe znaki, ale nie nową linię.

Do tej pory uciekałem się [ \t]. Czy istnieje mniej niezręczny sposób?

JoelFan
źródło
4
BTW, te znaki są także „białe znaki”: [\r\f].
Eugene Yarmash,
2
@eugeney czy ktoś nadal robi przesyłanie formularzy? (\ f's)
Aran Mulholland
1
@AranMulholland: Każdy, kto ma drukarkę zorientowaną na znaki. Większość drukarek ma tryb znakowy, a także PostScript lub jakikolwiek inny interfejs Hewlett Packard, i aby rzucić stronę, wysyłasz formularz.
Borodin
1
@Borodin Hewlett Packard's nazywa się PCL (Printer Control Language).
CB_Ron

Odpowiedzi:

182

Perl wersje 5.10 i później zależne wsparcie klas postaci pionowej i poziomej, \va \h, jak również ogólny spacje klasa znaków\s

Najczystszym rozwiązaniem jest użycie poziomej klasy znaków białych znaków \h. Spowoduje to dopasowanie tabulacji i spacji z zestawu ASCII, nierozdzielania spacji z rozszerzonego ASCII lub dowolnego z tych znaków Unicode

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

Pionowa przestrzeń wzór \vjest mniej przydatna, ale pasuje do tych znaków

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

Istnieje siedem pasujących znaków pionowych białych znaków \vi osiemnaście pasujących znaków poziomych \h. \sdopasowuje dwadzieścia trzy znaki

Wszystkie znaki białych znaków są pionowe lub poziome, bez nakładania się, ale nie są odpowiednimi podzestawami, ponieważ \hrównież pasują do U + 00A0 BEZ PRZERWU, a \vtakże pasują do U + 0085 NASTĘPNA LINIA, z których żaden nie jest dopasowany\s

Borodin
źródło
7
\hdziała tylko w obsługiwanych językach PCRE.
Avinash Raj
14
@AvinashRaj: To pytanie dotyczy Perla, który z pewnością obsługuje PCRE
Borodin
2
@AvinashRaj: Tyle że [[:blank:]]nie pasuje do spacji bez przerwy -  lub"\xA0"
Borodin
6
Chcę wspomnieć, że \hdziałało idealnie w moim przypadku użycia, który szukał / zamienił w Notepad ++ na co najmniej 1 ciągłym spacji nie nowej linii. Nic innego (proste) nie działało.
squidbe
8
To, co sprawia, że ​​Perl jest \hnieco niestandardowy, to jego włączenie MONGOLIAN VOWEL SEPARATOR. Unicode nie uważa tego za spację. Z tego powodu Perl \hróżni się od POSIX blank( [[:blank:]]w Perlu, \p{Blank}w Javie) i Java 8 \h. Trzeba przyznać, że to przypadek na krawędzi.
Aleksandr Dubinsky,
362

Użyj podwójnie ujemnego:

/[^\S\r\n]/

Oznacza to, że nie-spacja (duża litera S uzupełnia) lub zwrot-przewóz lub brak nowej linii. Dystrybucja zewnętrzna nie ( tj . Uzupełniająca^ w klasie postaci) z prawem De Morgana , jest to równoważne z „białymi spacjami, ale nie znakiem powrotu karetki lub znakiem nowej linii”. Włączenie zarówno wzorca, jak \ri \nwzorca poprawnie obsługuje wszystkie konwencje nowego wiersza Uniksa (LF), klasycznego Mac OS (CR) i DOS-ish (CR LF) .

Nie musisz mi wierzyć na słowo:

#! /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";
}

Wynik:

„” => dopasowanie
„\ f” => dopasowanie
„\ t” => dopasowanie
„\ r” => brak dopasowania
„\ n” => brak dopasowania

Zwróć uwagę na wyłączenie karty pionowej, ale zostało to rozwiązane w wersji 5.18 .

Przed zbyt surowym sprzeciwem dokumentacja Perla używa tej samej techniki. Przypis w sekcji „Białe znaki” w perlrecharclass brzmi:

W wersjach wcześniejszych niż Perl v5.18 \snie pasował do zakładki pionowej. [^\S\cK](niejasno) pasuje do tego, co \stradycyjnie robiono.

Ta sama sekcja perlrecharclass sugeruje również inne podejścia, które nie obrażą sprzeciwu nauczycieli języków obcych przed podwójnymi negatywami.

Poza regułami ustawień regionalnych i Unicode lub gdy /aprzełącznik działa, „ \spasuje [\t\n\f\r ]i, począwszy od Perla v5.18, pionowa karta \cK”. Odrzuć \ri \npozostaw, /[\t\f\cK ]/aby dopasować białe znaki, ale nie nową linię.

Jeśli twój tekst to Unicode, użyj kodu podobnego do podanego poniżej, aby zbudować wzór z tabeli w wyżej wymienionej sekcji dokumentacji .

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;
}

Inne aplikacje

Sztuczka podwójnie ujemna jest również przydatna do dopasowywania znaków alfabetycznych. Pamiętaj, że \wpasuje do „znaków słownych”, znaków alfabetycznych oraz cyfr i podkreślników. My, brzydcy Amerykanie, czasami chcemy to napisać, powiedzmy,

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

ale podwójnie ujemna klasa znaków może respektować ustawienia regionalne:

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

Wyrażenie „znak słowa, ale nie cyfry lub podkreślenia” w ten sposób jest nieco nieprzejrzyste. Klasa znaków POSIX komunikuje zamiar bardziej bezpośrednio

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

lub z właściwością Unicode, jak sugerował szbalint

if (/\p{Letter}+/) { ... }
Greg Bacon
źródło
4
Sprytne, ale zachowanie jest bardzo zaskakujące i nie rozumiem, jak jest mniej niezręczne.
Qwertie,
7
@Qwertie: co jest zaskakujące? Mniej niezręczny niż co?
ysth
9
Wyjątkowo okropny.
9
To jest bardzo dobre. Zgodnie z żądaniem dopasowujesz białe znaki (nie tylko niektóre białe znaki) i wykluczasz znak przejścia do nowego wiersza. Twoje rozwiązanie nie dotyczy samego pytania: „jakie są znaki białych znaków”, jak nie powinno. Właśnie tego szukałem. (Jak zauważył @Rory, a „nowej linii” może także zawierać \r, np na Windows, więc uważają, najtańsza te z meczu jak dobrze: /[^\S\r\n]/)
Timo
1
Z pewnością zaspokoi to potrzeby PO i praktycznie każdego, kto szuka tego pytania (w każdym razie anglojęzyczni). Ale to wciąż zła odpowiedź. Po prostu nie ma usprawiedliwienia dla korzystania z tego rozwiązania, gdy \hjest ono dostępne.
Alan Moore,
49

Odmiana odpowiedzi Grega, która obejmuje również zwrot karetki:

/[^\S\r\n]/

Ten wyrażenie regularne jest bezpieczniejsze niż /[^\S\n]/bez \r. Moje rozumowanie jest takie, że Windows używa \r\nnowych linii, a Mac OS 9 używany \r. Jest mało prawdopodobne, aby znaleźć \rbez \ndzisiejszych czasach, ale jeśli nie znajdziesz, to nie może oznaczać niczego oprócz znaku nowej linii. Zatem, ponieważ \rmoże oznaczać nowy wiersz, powinniśmy go również wykluczyć.

Rory O'Kane
źródło
1
+1 rozwiązanie Grega doprowadziło do uszkodzenia mojego tekstu, twoje działało dobrze.
Timo Huovinen,
Możesz być zaskoczony, jak wiele programów nadal używa „\ r” do zakończenia linii. Czasami zajęło mi trochę czasu, aby zorientować się, że mój problem polega na tym, że plik ich używał. Albo że używał kodowania znaków MacRoman ...
mivk
2
wygląda na to, że @Greg po raz pierwszy „źle” to zmieniło i nie przyznało ci uznania. Właśnie dlatego tutaj jestem entuzjastą.
Andre Elrico
14

Poniższy regex pasowałby do białych spacji, ale nie do nowego znaku linii.

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

PRÓBNY

Jeśli chcesz również dodać znak powrotu karetki, dodaj go \rwraz z |operatorem wewnątrz przeczącej perspektywy.

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

PRÓBNY

Dodaj +po grupie, która nie została przechwycona, aby dopasować jedną lub więcej białych spacji.

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

PRÓBNY

Nie wiem, dlaczego ludzie nie wspomnieli o klasie znaków POSIX, [[:blank:]]która pasuje do poziomych białych znaków ( spacji i tabulatorów ). Ta klasa chracter POSIX będzie działać na BRE ( Basic REgular Expressions ), ERE ( Extended Regular Expression ), PCRE ( Perl Compatible Regular Expression ).

PRÓBNY

Avinash Raj
źródło
To najlepsze rozwiązanie!
loretoparisi
13

To, czego szukasz, to blankklasa znaków POSIX . W Perlu jest określany jako:

[[:blank:]]

w Javie (nie zapomnij włączyć UNICODE_CHARACTER_CLASS):

\p{Blank}

W porównaniu z podobnym \h, POSIX blankjest obsługiwany przez kilka kolejnych silników wyrażeń regularnych ( odniesienie ). Główną zaletą jest to, że jego definicja została ustalona w załączniku C: Właściwości kompatybilności wyrażeń regularnych Unicode i standard we wszystkich odmianach regularnych obsługujących Unicode. (Na przykład w Perlu \hdecyduje się dodatkowo dołączyć MONGOLIAN VOWEL SEPARATOR.) Jednak argumentem przemawiającym za \htym jest to, że zawsze wykrywa znaki Unicode (nawet jeśli silniki nie zgadzają się co do tego), podczas gdy klasy znaków POSIX są często domyślnie ASCII -tylko (jak w Javie).

Problem polega jednak na tym, że nawet trzymanie się Unicode nie rozwiązuje problemu w 100%. Rozważ następujące znaki, które nie są uważane za białe znaki w Unicode:

  • U + 180E MONGOLIJSKI SEPARATOR GŁÓWNY

  • U + 200B ZERO WIDTH SPACE

  • U + 200C SZEROKOŚĆ ZEROWA NIE JOINER

  • ŁĄCZNIK SZEROKOŚCI U + 200D

  • U + 2060 WORD JOINER

  • U + FEFF ZERO WIDTH PRZESTRZEŃ NIEWYŁUSZAJĄCA

    Zaczerpnięte z https://en.wikipedia.org/wiki/White-space_character

Wyżej wymieniony mongolski separator samogłosek nie jest zawarty z tego, co prawdopodobnie jest dobrym powodem. Wraz z 200C i 200D występuje w słowach (AFAIK), a zatem łamie kardynalną zasadę, której przestrzegają wszystkie inne białe znaki: możesz za jej pomocą tokenizować. Są bardziej jak modyfikatory. Jednak ZERO WIDTH SPACE, WORD JOINERorazZERO WIDTH NON-BREAKING SPACE (jeśli jest stosowany jako inny niż znak kolejności bajtów) pasuje do reguły białe znaki w mojej książce. Dlatego włączam je do mojej poziomej klasy białych znaków.

W Javie:

static public final String HORIZONTAL_WHITESPACE = "[\\p{Blank}\\u200B\\u2060\\uFFEF]"
Aleksandr Dubinsky
źródło
Musisz dodać odpowiednie flagi kompilacji wyrażenia regularnego do kompilacji Java i uruchomić Javę 7 lub nowszą. W każdym razie pytanie nie dotyczyło w ogóle Javy ani PCRE, więc jest to nieistotne.
tchrist
@ tchrist Dziękujemy za zwrócenie na to uwagi. Zaktualizuję swoją odpowiedź. Nie zgadzam się jednak, że moja odpowiedź jest nieistotna. Nieistotne jest to, że perlznacznik w pierwotnym pytaniu.
Aleksandr Dubinsky
1
@AleksandrDubinsky, \ p {Blank} nie jest obsługiwany w JavaScript, więc zdecydowanie nie jest „standardem dla wszystkich smaków wyrażenia regularnego” -1
Valentin Vasilyev
Najbardziej pouczające. Niepokoi mnie to, że nie istnieje ogólna i kompletna krótka klasa znaków „pozioma biała spacja” i że [\p{Blank}\u200b\u180e]wymagane są horrory . Trzeba przyznać, że separator samogłosek nie jest uważany za znak spacji, ale dlaczego nie ma spacji o zerowej szerokości w klasach takich jak \si \p{Blank}, bije mnie.
Timo,
Dalsze działania: czytam, że oba są uważane za „neutralne dla granic”, chociaż to nie wyjaśnia, dlaczego .
Timo,
-4

m/ /gpo prostu daj miejsce / /, a zadziała. Lub użyj \S- zastąpi wszystkie znaki specjalne, takie jak tabulator, znaki nowej linii, spacje i tak dalej.

saiprathapreddy.obula
źródło