web-dev-qa-db-ja.com

空白は一致するが改行は一致しない

空白ではなく改行に一致させたい場合があります。

これまで、私は[ \t]に頼ってきました。それほど厄介な方法はありますか?

240
JoelFan

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に一致する7個の垂直方向の空白文字と、\hに一致する18個の水平方向の空白文字があります。 \sは23文字に一致します

すべての空白文字はverticalまたはhorizo​​ntalのいずれかですが、\hもU + 00A0 NO-BREAK SPACEに一致し、\vもU +に一致するため、適切なサブセットではありません0085 NEXT LINE、どちらも\sに一致しない

159
Borodin

二重否定を使用します。

/[^\S\r\n]/

つまり、空白ではない(大文字のSが補う)またはキャリッジリターンではない、または改行ではない。 De Morganの法則 で外側のnot(ie、文字クラスの^を補完する)を配布するパターンに\r\nの両方を含めると、Unix(LF)、従来のMac OS(CR)、DOS-ish( CR LF) 改行規則

私の言葉を受け入れる必要はありません:

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

出力:

"" => match 
 "\ f" => match 
 "\ t" => match 
 "\ r" => no match 
 "\ n "=>一致なし

垂直タブが除外されていることに注意してください。ただし、これは v5.18で対応 です。

厳しく反対する前に、Perlのドキュメントは同じテクニックを使用しています。 perlrecharclassの「Whitespace」セクション の脚注

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:]]+/) { ... }

または szbalint が推奨されるUnicodeプロパティ

if (/\p{Letter}+/) { ... }
324
Greg Bacon

Gregの答え のバリエーションには、キャリッジリターンも含まれます。

/[^\S\r\n]/

この正規表現は、/[^\S\n]/を持たない\rよりも安全です。私の推論では、Windowsは改行に\r\nを使用し、Mac OS 9は\rを使用したということです。最近、\rなしで\nを見つけることはほとんどありませんが、それを見つけたとしても、改行以外の意味はありません。したがって、\rは改行を意味する可能性があるため、これも除外する必要があります。

43
Rory O'Kane

探しているのはPOSIX blank文字クラスです。 Perlでは、次のように参照されます。

[[:blank:]]

Java(UNICODE_CHARACTER_CLASSを有効にすることを忘れないでください):

\p{Blank}

類似の\hと比較して、POSIX blankは、さらにいくつかの正規表現エンジンでサポートされています( reference )。主な利点は、その定義が 付録C:Unicode正規表現の互換性プロパティ に固定されており、Unicodeをサポートするすべての正規表現フレーバーの標準であることです。 (例えばPerlでは、\hMONGOLIAN VOWEL SEPARATORを追加することを選択します。)ただし、\hを支持する引数は、Unicode文字を常に検出することです(エンジンがどちらに同意しなくても)デフォルトではASCIIのみ(Javaのように)。

しかし問題は、ユニコードに固執しても問題を100%解決できないことです。 Unicodeで空白と見なされない次の文字を考慮してください。

  • U + 180Eモンゴルのボウセパレーター
  • U + 200Bゼロ幅スペース
  • U + 200Cゼロ幅非ジョイナー
  • U + 200Dゼロ幅ジョイナー
  • U + 2060 Word JOINER
  • U + FEFF ZERO WIDTH非破壊スペース

    https://en.wikipedia.org/wiki/White-space_character から取得

前述のモンゴル語の​​母音セパレータは、おそらく正当な理由のために含まれていません。これは、200Cおよび200Dとともに、単語内で発生するため(AFAIK)、したがって、他のすべての空白が従う基本的な規則を破ります。これでトークン化できます。それらは修飾子のようなものです。ただし、ZERO WIDTH SPACEWord JOINER、およびZERO WIDTH NON-BREAKING SPACE(バイトオーダーマーク以外として使用されている場合)は、私の本の空白ルールに適合しています。したがって、水平方向の空白文字クラスにそれらを含めます。

Javaの場合:

static public final String HORIZONTAL_WHITESPACE = "[\\p{Blank}\\u200B\\u2060\\uFFEF]"
11

以下の正規表現は空白文字に一致しますが、改行文字には一致しません。

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

DEMO

キャリッジリターンも追加する場合は、負の先読み内で\r演算子を使用して|を追加します。

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

DEMO

非キャプチャグループの後に+を追加して、1つ以上の空白に一致させます。

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

DEMO

水平方向の空白(のスペースとタブ)に一致するPOSIX文字クラス[[:blank:]]について言及しなかった理由がわかりません。このPOSIX特性クラスは、BRE(Basic REgular Expressions)、ERE(Extended Regular Expression)、PCRE(Perl互換正規表現)。

DEMO

10
Avinash Raj