Соответствует пробелу, но не переводам строки

Я иногда хочу найти пробел, но не перевод строки.

До сих пор я прибегал к [\ t] . Есть ли менее неловкий путь?

257
задан Borodin 6 July 2016 в 01:24
поделиться

1 ответ

Используйте двойное отрицание:

/[^\S\r\n]/

То есть, не-не-пробел (дополнение заглавной буквы S), или без возврата каретки, или без символа новой строки.Распространение внешнего not ( т.е. , дополняющее ^ в классе символов) с законом Де Моргана , это эквивалентно «пробелу, но не возврату каретки или новой строке. . » Включение в шаблон как \ r , так и \ n правильно обрабатывает все Unix (LF), классическую Mac OS (CR) и DOS-ish (CR LF) новой строки соглашения .

Не нужно верить мне на слово:

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

Вывод:

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

Обратите внимание на исключение вертикальной табуляции, но это , адресованное в v5.18 .

Прежде чем возражать слишком резко, документация Perl использует ту же технику. Сноска в разделе «Пробел» perlrecharclass гласит:

До Perl v5.18 \ s не соответствовал вертикальной табуляции. [^ \ S \ cK] (неясно) совпадает с тем, что традиционно делал \ s .

Тот же раздел perlrecharclass также предлагает другие подходы, которые не оскорбят возражений учителей языка против двойного отрицания.

За пределами правил локали и Unicode или когда действует переключатель / a , « \ s соответствует [\ t \ n \ f \ r] и, начиная с Perl v5.18, вертикальная вкладка \ cK ». Отбросьте \ r и \ n , чтобы оставить / [\ t \ f \ cK] / для сопоставления пробелов, но не новой строки.

Если ваш текст - Unicode, используйте код, аналогичный приведенному ниже, чтобы построить шаблон из таблицы в вышеупомянутого раздела документации .

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

Другие приложения

Трюк с двойным отрицанием также удобен для сопоставления буквенных символов. Помните, что \ w соответствует «символам слова», буквенным символам и цифрам и знаку подчеркивания. Мы, уродливые американцы, иногда хотим записать это как, скажем,

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

, но класс двойных отрицательных символов может уважать локаль:

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

Выражение «символ слова, но не цифра или подчеркивание» таким способом немного непрозрачно. Символьный класс POSIX передает намерение более напрямую

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

или с помощью свойства Unicode, как szbalint предлагается

if (/\p{Letter}+/) { ... }
337
ответ дан 23 November 2019 в 02:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: