空白に一致しますが、改行には一致しません 質問する

空白に一致しますが、改行には一致しません 質問する

空白を一致させたいけれど、改行を一致させたくない場合があります。

これまでは に頼ってきました[ \t]。もっと気まずくない方法はないでしょうか?

ベストアンサー1

まとめ

  • 多くの非ペクレエンジンでは二重否定を使用します。[^\S\r\n]
  • ASCII を扱う場合は、何が欲しいかを述べてください[\t\f\cK ]
  • 水平方向の空白スペースに一致させるために使用します\hPerl v5.10.0以降(2007年公開)
  • Unicodeプロパティ:\p{Blank}または\p{HorizSpace}
  • Unicode で何を望んでいるのかを明確にする(ただし、実際にはそうする必要はありません)
  • 二重否定とUnicodeプロパティのその他の使用法

二重否定

パターンを他のエンジン、特にPerl互換または をサポートしない場合は\h、二重否定として表現します。

[^\S\r\n]

つまり、空白文字ではない(大文字のS補完)か、改行文字ではない、または改行文字ではないということです。外側のnot(つまり^括弧付き文字クラス) とド・モルガンの法則は、から\rとを減算するのと同じです。パターンに復帰と改行の両方を含めると、Unix (LF)、クラシックMac OS (CR)、DOS風 (CRLF) のすべてを正しく処理できます。\n\s改行規則

私の言うことを信じる必要はありません。

#! /usr/bin/env perl

use strict;
use warnings;

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従来のものと一致。


直接的なアプローチ: ASCII 版

perlrecharclass の「空白」セクションまた、二重否定に反対する文法教師を怒らせない他のアプローチも提案しています。

言いたくないことよりも、言いたいことを言いましょう。

ロケールとUnicodeのルール外の場合、または/aまたは/aaスイッチが有効になっている場合、「 」\s[\t\n\f\r ]、Perl v5.18 以降では垂直タブ\cK」に一致します。

空白に一致し、改行には一致しない (広義) 場合は、 を破棄して\rを残し\nます[\t\f\cK ]


水平方向の空白

perlre の「文字クラスとその他の特別なエスケープ」セクション含まれるもの

  • \h水平方向の空白
  • \H水平方向の空白ではない

Unicode プロパティ

前述のperlreドキュメント\h\Hを参照するperlunicode ドキュメントここでは、便利な Unicode プロパティのファミリーについて説明します。

  • \p{Blank}
    • \hこれはおよびと同じです\p{HorizSpace}。水平方向の間隔を変更する文字です。
  • \p{HorizSpace}
    • \hこれはおよびと同じです\p{Blank}。水平方向の間隔を変更する文字です。

直接的なアプローチ: Unicode 版

テキストがUnicodeの場合は、以下のサブのようなコードを使用して、表からパターンを構築します。perlrecharclass の「空白」セクション

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;
}

上記は完全性を保つためのものです。手書きで書くのではなく、Unicode プロパティを使用してください。


二重否定と Unicode プロパティのその他の応用

二重否定のトリックは、アルファベット文字の一致にも便利です。\w単語文字、アルファベット文字数字、アンダースコアに一致することを覚えておいてください。私たち醜いアメリカ人は、次のように書きたくなることがあります。

if (/[A-Za-z]+/) { ... }

ただし、二重否定の文字クラスはロケールを尊重できます。

if (/[^\W\d_]+/) { ... }

このように「単語文字だが数字やアンダースコアではない」と表現するのは少しわかりにくい。POSIX文字クラスは、より直接的に意図を伝えます。

if (/[[:alpha:]]+/) { ... }

またはUnicodeプロパティでシュバリント提案された

if (/\p{Letter}+/) { ... }

ピングイ二重否定文字クラスをネストして効果的に変更する方法を尋ねた\s

/(\+|0|\()[\d()\s-]{6,20}\d/g

私が思いつく限りのベスト|代替としてを使用し、\s他のブランチに移動します。

/(\+|0|\()(?:[\d()-]|[^\S\r\n]){6,20}\d/g

おすすめ記事