Збігайте пробіли, але не нові рядки


277

Я іноді хочу відповідати пробілу, але не новому рядку.

Поки що я вдавався [ \t]. Чи є менш незручний спосіб?


4
До речі, ці символи також «пробіл»: [\r\f].
Євген Ярмаш

2
@eugeney хтось досі робить канали форми? (\ f's)
Аран Малхолланд

1
@AranMulholland: той, хто має принтер, орієнтований на символи. Більшість принтерів мають символьний режим, а також PostScript або будь-який інший інтерфейс Hewlett Packard, і щоб перекинути сторінку, ви надсилаєте подачу форми.
Бородін

1
@Borodin Hewlett Packard називається PCL (Мова управління принтером).
CB_Ron

Відповіді:


182

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


7
\hпрацює лише на мовах, які підтримує PCRE.
Avinash Raj

14
@AvinashRaj: Це питання стосується Perl, який, безумовно, підтримує PCRE
Borodin

2
@AvinashRaj: За винятком того, [[:blank:]]що не відповідає простору без перерви -  або"\xA0"
Бородін

6
Хочу згадати, що \hпрекрасно працював у моєму випадку використання, який робив пошук / заміну в Блокноті ++ на 1 або більше суміжних просторах, які не є новими рядками. Нічого іншого (просто) не працювало.
кальмар

8
Що робить Perl \hтрохи нестандартним, це його включення MONGOLIAN VOWEL SEPARATOR. Unicode не вважає це пробілом. З цієї причини Perl \hвідрізняється від POSIX blank( [[:blank:]]у Perl, \p{Blank}на Java) та Java 8 \h. Справді, це крайній випадок.
Олександр Дубінський

362

Використовуйте подвійний мінус:

/[^\S\r\n]/

Тобто, не-пробільний простір (з великої літери доповнює) або не-перевезення-повернення чи не-нова лінія. Розподіляючи зовнішнє не ( тобто доповнення ^до класу символів) із законом Де Моргана , це еквівалентно "пробілу, але не поверненню каретки чи новій лінії ". Включаючи як \rі \nв шаблон, правильно обробляє всі конвенції Unix (LF), класичні Mac OS (CR) та DOS-ish (CR LF) newline .

Не потрібно сприймати моє слово за це:

#! /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";
}

Вихід:

"" => збіг
"\ f" => збіг
"\ t" => збіг
"\ r" => не відповідає
"\ n" => немає відповідності

Зверніть увагу на виключення вертикальної вкладки, але це вирішено в v5.18 .

Перш ніж занадто різко заперечувати, документація Perl використовує ту саму методику. Виноска в розділі «Прогалини» в perlrecharclass читає

До Perl v5.18 \sне відповідав вертикальній вкладці. [^\S\cK](незрозуміло) відповідає тому, що \sробили традиційно.

Цей самий розділ perlrecharclass також пропонує інші підходи, які не ображатимуть протиставлення вчителів мови подвійним негативам.

Поза зовнішніми правилами та правилами Unicode або коли діє /aперемикач, " \sвідповідає [\t\n\f\r ]і, починаючи з Perl v5.18, вертикальної вкладки \cK". Відмовтеся \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}+/) { ... }

4
Розумна, але поведінка дуже дивно, і я не бачу, як це менш незручно.
Qwertie

7
@Qwertie: що дивного? Менш ніяково, ніж що?
ysth

9
Чудово жахливо.

9
Це дуже добре. Як вимагається, ви збігаєте пробіл (не лише деякі символи пробілу) і виключаєте символ подачі рядка. Ваше рішення не стосується себе питання: "які символи пробілу існують", як і не повинно. Це саме те, що я шукав. (Як було відзначено @Rory, а «новий рядок» може також включати в себе \r, наприклад , на Windows, так вважають exluding ті від матчу , а також: /[^\S\r\n]/)
Timo

1
Це, безумовно, задовольнить потреби ОП та практично всіх інших, хто шукає це питання (так чи інакше говорять англійською). Але це все-таки погана відповідь. Просто немає приправ для використання цього рішення, коли \hвоно доступне.
Алан Мур

49

Варіант відповіді Грега, що включає також повернення вагона:

/[^\S\r\n]/

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


1
+1 Рішення Грега зіпсувало мій текст, ваше добре працювало.
Тімо Хуовінен

Ви можете бути здивовані тим, скільки програм все ще використовують "\ r" для закінчень рядків. Іноді мені знадобилося певний час, щоб зрозуміти, що моя проблема полягала в тому, що файл використовував ці. Або що він використовував кодування символів MacRoman ...
mivk

2
схоже, що @Greg спочатку його "неправильно" змінив і не видав вам кредит. Ось чому імпонування тут.
Андре Елріко

14

Наведений нижче регекс відповідатиме пробілами, але не має нового символу рядка.

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

DEMO

Якщо ви хочете додати повернення каретки, тоді також додайте \rразом з |оператором всередині негативного пошуку.

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

DEMO

Додайте +після групи, що не захоплює, щоб відповідати одному або декілька пробілів.

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

DEMO

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

DEMO


Це найкраще рішення!
loretoparisi

13

Що ви шукаєте, це blankклас символів POSIX . У Perl це посилання:

[[:blank:]]

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

\p{Blank}

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

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

  • U + 180E МОНГОЛЬСЬКИЙ СЕПАРАТОР ВОЛУ

  • U + 200B ZERO WIDTH SPACE

  • U + 200C ZERO WIDTH НЕ ПРИЄДНАЙТЕСЬ

  • U + 200D ШІРНИЙ ПРИЄДНИЙ ЗЕРО

  • U + 2060 СЛОВНИЙ СПІЛЬНИК

  • U + FEFF ZERO ШИРОТИЙ НЕЗАПАДНИЙ ПРОСТОР

    Взято з 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]"

Вам потрібно додати відповідні прапори компіляції regexp до компіляції Java та запустити Java 7 або новішу версію. У будь-якому випадку, питання взагалі не стосувалося Java чи PCRE, тому це все несуттєво.
tchrist

@tchrist Дякую, що вказали на це. Я оновлю свою відповідь. Я не погоджуюся, що моя відповідь не має значення. Що несуттєво, це perlтег в оригінальному запитанні.
Олександр Дубінський

1
@AleksandrDubinsky, \ p {Blank} не підтримується в JavaScript, тому напевно не "стандартний для всіх ароматів регулярного генерування" -1
Валентин Васильєв,

Найбільш інформативні. Я вважаю занепокоєнням знати, що загального та повного класу скорочень символів "горизонтального пробілу" не існує, і що [\p{Blank}\u200b\u180e]потрібні подібні жахи . Справді, є сенс, що роздільник голосних не вважається символом пробілу, але чому простір нульової ширини не в таких класах, як, \sі \p{Blank}мене б'є.
Тимо

Продовження: Я прочитав, що обидва вважаються "гранично нейтральними", хоча це не пояснює, чому .
Тимо

-4

m/ /gпросто дайте місце в / /, і воно спрацює. Або використовувати \S- він замінить усі спеціальні символи, такі як вкладка, нові рядки, пробіли тощо.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.