Сопоставить пробелы, но не символы новой строки
Я иногда хочу совместить пробелы, но не новую строку.
До сих пор я прибегал к [ \t]
. Есть ли менее неудобный способ?
Ответы
Ответ 1
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
Ответ 2
Использовать двойное отрицание:
/[^\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}+$/) { ... }
Ответ 3
Вариант Gregs answer, который включает также возврат каретки:
/[^\S\r\n]/
Это регулярное выражение безопаснее, чем /[^\S\n]/
без \r
. Мои рассуждения состоят в том, что Windows использует \r\n
для новых строк, а для Mac OS 9 используется \r
. Вы вряд ли найдете \r
без \n
в настоящее время, но если вы его найдете, это не может означать ничего, кроме новой строки. Таким образом, поскольку \r
может означать новую строку, мы должны ее исключить.
Ответ 4
Что вы ищете, это класс символов 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%. Рассмотрим следующие символы, которые не считаются пробелами в Юникоде:
Вышеупомянутый монгольский разделитель гласных не включен для того, что, вероятно, является веской причиной. Он, наряду с 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]"
Ответ 5
Ниже regex будет соответствовать пробелам, но не новому символу строки.
(?:(?!\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 Compatible Regular Expression).
DEMO
Ответ 6
m/ /g
просто укажите пробел в / /
, и он будет работать. Или используйте \S
- он заменит все специальные символы, такие как вкладка, новые строки, пробелы и т.д.