Сопоставлять пробелы, но не новые строки

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

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

6 ответов


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

самое чистое решение-использовать горизонтальные пробельные символы класс персонажа \h. Это будет соответствовать вкладке и пробелу из набора ASCII, неразрывному пространству из расширенного ASCII или любому из этих символов Юникода

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 без перерыва и \v также соответствует U + 0085 следующая строка, ни одна из которых не соответствует \s


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

/[^\S\n]/

чтобы избежать различий в платформе предупрежден в perlport относительно отображений \r и \n:

/[^\S\x0a\x0d]/

то есть, не-не-пробел или не-новая строка и аналогичные для шаблона, который исключает CR и NL.

распределение внешнего не (то есть, дополняющего ^ в классе символов) с закон де Моргана, это равносильно "пробел, а не возвращение кареты и не новая линия", но не верьте мне на слово:

#! /usr/bin/env perl

use strict;
use warnings;

use 5.005;  # for qr//

my $ws_not_nl = qr/[^\S\x0a\x0d]/;

for (' ', '\f', '\t', '\r', '\n') {
  my $qq = qq["$_"];
  printf "%-4s => %s\n", $qq,
    (eval $qq) =~ $ws_not_nl ? "match" : "no match";
}

выход:

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

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

этот трюк также удобен для сопоставления алфавитных символов. Запомните это \w матчи "символов слов," буквы а и цифры и подчеркивания. Мы, уроды-американцы, иногда хотим написать это как, скажи,

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

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

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

это немного непрозрачно, поэтому класс символов POSIX может быть лучше выражать намерение

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

или szbalint предложил

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

вариант ответ Грега это включает возврат каретки:

/[^\S\r\n]/

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


то, что вы ищете, это POSIX blank класс персонажа. В Perl он ссылается как:

[[:blank:]]

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

\p{Blank}

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

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

  • U + 180E МОНГОЛЬСКИЙ ГЛАСНЫЙ СЕПАРАТОР
  • U + 200B ПРОСТРАНСТВО НУЛЕВОЙ ШИРИНЫ
  • U + 200C ZERO NON-JOINER ШИРИНЫ
  • U + 200D НУЛЕВАЯ ШИРИНА СТОЛЯРА
  • U + 2060 СЛОВО СТОЛЯР
  • 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]"

ниже регекс соответствует пробелы, но не символ новой строки.

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

демо

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

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

демо

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

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

демо

Я не знаю, почему вы не упомянули класс символов POSIX [[:blank:]] который соответствует любым горизонтальным пробелам (пробелы и знаки табуляции). Этот класс POSIX chracter будет работать на BRE (Основные Регулярные Выражения), ERE (Расширенное Регулярное Выражение), PCRE (Perl Совместимое Регулярное Выражение).

демо


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