Я иногда хочу совместить пробелы, но не новую строку.
До сих пор я прибегал к [ \t]
. Есть ли менее неудобный способ?
Я иногда хочу совместить пробелы, но не новую строку.
До сих пор я прибегал к [ \t]
. Есть ли менее неудобный способ?
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 NEXT LINE, ни один из которых соответствуют \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}+$/) { ... }
Вариант Gregs answer, который включает также возврат каретки:
/[^\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 и стандарт во всех вариантах регулярных выражений, которые поддерживают Unicode. (В Perl, например, \h
выбирает дополнительно включить MONGOLIAN VOWEL SEPARATOR
.) Однако аргумент в пользу \h
заключается в том, что он всегда обнаруживает символы Unicode (даже если двигатели не согласны с ними) в то время как классы символов POSIX часто по умолчанию используются только ASCII (как в Java).
Но проблема в том, что даже придерживаться Unicode не решает проблему на 100%. Рассмотрим следующие символы, которые не считаются пробелами в Юникоде:
U + FEFF ZERO WIDTH N-BREAKING SPACE
Взято из 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]"
Ниже regex будет соответствовать пробелам, но не новому символу строки.
(?:(?!\n)\s)
Если вы хотите добавить возврат каретки, добавьте \r
с оператором |
внутри отрицательного вида.
(?:(?![\n\r])\s)
Добавьте +
после того, как группа, не связанная с захватом, будет соответствовать одному или нескольким пробелам.
(?:(?![\n\r])\s)+
Я не знаю, почему вы не смогли упомянуть класс символов POSIX [[:blank:]]
, который соответствует любым горизонтальным пробелам (пробелам и вкладкам). Этот класс POSIX chracter будет работать на BRE (Basic REgular Expressions), ERE (Extended Regular Expression), PCRE (Perl Compatible Regular Expression).
m/ /g
просто укажите пробел в / /
, и он будет работать. Или используйте \S
- он заменит все специальные символы, такие как вкладка, новые строки, пробелы и т.д.