Соответствует пробелу, но не переводам строки

169

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

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

  • 4
    Кстати, эти символы также являются «пробелами»: [\r\f] .
  • 2
    @eugeney кто-нибудь все еще делает фиды? (\ Е в)
Показать ещё 2 комментария
Теги:

6 ответов

118
Лучший ответ

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

  • 5
    \h работает только на тех языках, которые поддерживают PCRE .
  • 14
    @AvinashRaj: Этот вопрос касается Perl, который, безусловно, поддерживает PCRE.
Показать ещё 12 комментариев
229

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

/[^\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}+$/) { ... }
  • 4
    Умно, но поведение очень удивительно, и я не вижу, как это менее неловко.
  • 5
    @Qwertie: что удивительного? Менее неловко, чем что?
Показать ещё 5 комментариев
37

Вариант Gregs answer, который включает также возврат каретки:

/[^\S\r\n]/

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

  • 1
    +1 Решение Грега испортило мой текст, твое сработало нормально.
  • 0
    Вы можете быть удивлены тем, сколько программ по-прежнему используют «\ r» для окончания строк. Иногда мне требовалось время, чтобы понять, что моя проблема была в том, что файл использовал их. Или что он использовал кодировку символов MacRoman ...
7

Ниже 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

7

Что вы ищете, это класс символов 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 + 180E МОНГОЛЬСКИЙ СЕПАРАТОР ПОТОКОВ
  • U + 200B ZERO WIDTH SPACE
  • U + 200C ZERO WIDTH NON-JOINER
  • U + 200D ZERO WIDTH JOINER
  • U + 2060 WORD JOINER
  • 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]"
  • 0
    Вам необходимо добавить соответствующие флаги компиляции regexp в компиляцию Java и использовать Java 7 или более позднюю версию. В любом случае, вопрос был не о Java или PCRE вообще, так что все это несущественно.
  • 0
    @tchrist Спасибо, что указали на это. Я обновлю свой ответ. Я не согласен, однако, что мой ответ не имеет значения. Что не имеет значения, так это тег perl в исходном вопросе.
Показать ещё 3 комментария
-5

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню