Я иногда хочу найти пробел, но не перевод строки.
До сих пор я прибегал к [\ t]
. Есть ли менее неловкий путь?
Используйте двойное отрицание:
/[^\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}+/) { ... }