Соответствовать пробелу, но не переводам строки - PullRequest
242 голосов
/ 12 августа 2010

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

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

Ответы [ 6 ]

317 голосов
/ 12 августа 2010

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

/[^\S\r\n]/

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

В том же разделе 1036 * perlrecharclass также предлагаются другие подходы, которые не будут оскорблять оппозицию учителей языка двойным негативам.

Вне локали и правил Unicode или когда действует переключатель /a, «\s соответствует [\t\n\f\r ] и, начиная с Perl v5.18, вертикальная вкладка, \cK». Discard \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}+/) { ... }
160 голосов
/ 21 сентября 2014

Perl версии 5.10 и более поздние поддерживают вспомогательные вертикальные и горизонтальные классы символов \v и \h, а также общий класс символов пробелов \s

Самое чистое решение - использовать горизонтальный пробел класс символов \h.Это будет соответствовать символу табуляции и пробелу из набора ASCII, неразрывному пробелу из расширенного ASCII или любому из этих символов 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

вертикальный пробел шаблон \v менее полезен, но соответствует этим символам

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

Существует семь вертикальных пробельных символов, которые соответствуют \v, и восемнадцать горизонтальных символов, которые соответствуют \h.\s соответствует двадцати трем символам

Все пробельные символы либо вертикальные , либо горизонтальные без перекрытия, но не являются правильными подмножествами, поскольку \h также соответствуетU + 00A0 NO-BREAK SPACE, и \v также соответствует U + 0085 СЛЕДУЮЩЕЙ ЛИНИИ, ни один из которых не соответствует \s

43 голосов
/ 19 июля 2013

Вариант Ответ Грега , который также включает возврат каретки:

/[^\S\r\n]/

Это регулярное выражение безопаснее, чем /[^\S\n]/ без \r. Я считаю, что Windows использует \r\n для перехода на новую строку, а Mac OS 9 использует \r. Вы вряд ли найдете \r без \n в наше время, но если вы его найдете, это не может означать ничего, кроме новой строки. Таким образом, поскольку \r может означать новую строку, мы также должны исключить ее.

11 голосов
/ 28 июля 2014

Что вам нужно, так это класс символов POSIX blank. В Perl это упоминается как:

[[:blank:]]

в Java (не забудьте включить UNICODE_CHARACTER_CLASS):

\p{Blank}

По сравнению с аналогичным \h, POSIX blank поддерживается еще несколькими механизмами регулярных выражений ( ссылка ). Основное преимущество заключается в том, что его определение зафиксировано в Приложении C: Свойства совместимости регулярных выражений Unicode и стандартно для всех разновидностей регулярных выражений, поддерживающих Unicode. (Например, в Perl \h решает дополнительно включить MONGOLIAN VOWEL SEPARATOR.) Однако аргумент в пользу \h заключается в том, что он всегда обнаруживает символы Юникода (даже если движки не соглашаются с какими), в то время как классы символов POSIX часто по умолчанию только для ASCII (как в Java).

Но проблема в том, что даже придерживание Unicode не решает проблему на 100%. Рассмотрим следующие символы, которые не считаются пробелами в Юникоде:

  • U + 180E Монгольский разделитель гласных
  • U + 200B ZERO WIDTH SPACE
  • U + 200C ШИРОКОМПОНЕНТСКАЯ НУЛЯ
  • U + 200D ZIRO WIRTH JOINER
  • U + 2060 WORD JOINER
  • U + FEFF с нулевой шириной неразрывного пространства

    Взято из https://en.wikipedia.org/wiki/White-space_character

Вышеупомянутый монгольский разделитель гласных не включен, что, вероятно, является веской причиной. Это, наряду с 200C и 200D, происходит в словах (AFAIK), и поэтому нарушает кардинальное правило, которому подчиняются все остальные пробелы: вы можете токенизировать с ним. Они больше похожи на модификаторы. Однако ZERO WIDTH SPACE, WORD JOINER и ZERO WIDTH NON-BREAKING SPACE (если они используются не как знак порядка байтов) соответствуют правилу пробелов в моей книге. Поэтому я включаю их в свой класс символов горизонтального пробела.

В Java:

static public final String HORIZONTAL_WHITESPACE = "[\\p{Blank}\\u200B\\u2060\\uFFEF]"
10 голосов
/ 21 сентября 2014

Следующее регулярное выражение будет соответствовать пробелам, но не символу новой строки.

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

DEMO

Если вы также хотите добавить возврат каретки, добавьте\r с оператором | внутри отрицательного взгляда.

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

DEMO

Добавьте + после группы без захвата, чтобы соответствовать одному илибольше пробелов.

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

DEMO

Я не знаю, почему вы, люди, не упомянули класс символов POSIX [[:blank:]], который соответствует любым горизонтальным пробелам ( пробелы и символы табуляции ).Этот класс POSIX chracter будет работать с BRE ( Basic REgular Expressions ), ERE ( Extended Regular Expression ), PCRE ( Perl-совместимое регулярное выражение ).

DEMO

0 голосов
/ 18 апреля 2014

m/ /g просто введите пробел в / /, и это будет работать.Или используйте \S - он заменит все специальные символы, такие как табуляция, новые строки, пробелы и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...