web-dev-qa-db-ja.com

空白以外の正規表現

文字列を一致させようとしているのは、bashのifステートメント内の正規表現です。以下のコード:

var='big'
If [[ $var =~ ^b\S+[a-z]$ ]]; then 
echo $var
else 
echo 'none'
fi

一致は、「b」で始まり、1つ以上の非空白文字が続き、文字a-zで終わる文字列である必要があります。文字列の先頭と末尾を一致させることはできますが、\ Sが空白以外の文字と一致するように機能しません。助けてくれてありがとう。

6
Fxbaez

非GNUシステムでは、以下が_\S_が失敗する理由を説明します:

_\S_はPCRE(Perl互換の正規表現)の一部です。シェルで使用される BRE(基本正規表現) または ERE(拡張正規表現) の一部ではありません。

ダブルブラケットテスト内のbash演算子_=~_ _[[_は、EREを使用します。

(通常の文字ではなく)EREで特別な意味を持つ文字は.[\()*+?{|^$だけです。特別なSはありません。より基本的な要素から正規表現を構築する必要があります:

_regex='^b[^[:space:]]+[a-z]$'
_

ブラケット式_[^[:space:]]__\S_ PCRE式 と同等です。

デフォルトの_\s_文字は、HT(9)、LF(10)、VT(11)、FF(12)、CR(13)、スペース(32)になりました。

テストは次のようになります。

_var='big'            regex='^b[^[:space:]]+[a-z]$'

[[ $var =~ $regex ]] && echo "$var" || echo 'none'
_

ただし、上記のコードは、たとえば_bißß_と一致します。選択されたロケールが(UNICODE)の場合、_[a-z]_にはabcdefghijklmnopqrstuvwxyz以外の文字が含まれるため。このような問題を回避するには、次を使用します。

_var='bißß'            regex='^b[^[:space:]]+[a-z]$'

( LC_ALL=C;
  [[ $var =~ $regex ]]; echo "$var" || echo 'none'
)
_

コードはリスト内の文字のみに一致します:最後の文字位置のabcdefghijklmnopqrstuvwxyzが、途中のその他の多くの文字にも一致します。 _bég_。


それでも、この_LC_ALL=C_の使用は他の正規表現の範囲に影響します。_[[:space:]]_はCロケールのスペースのみに一致します。

すべての問題を解決するには、各正規表現を個別に保つ必要があります。

_reg1=[[:space:]]   reg2='^b.*[a-z]$'           out=none

if                 [[ $var =~ $reg1 ]]  ; then out=none
Elif   ( LC_ALL=C; [[ $var =~ $reg2 ]] ); then out="$var"
fi
printf '%6.8s\t|' "$out"
_

これは次のようになります。

  • 入力(var)にスペースがない場合(現在のロケール)
  • bで始まり、_a-z_(Cロケールの場合)で終わることを確認してください。

どちらのテストも、正の範囲で行われることに注意してください(「範囲外」の範囲ではありません)。その理由は、いくつかの文字を否定すると、より多くの可能な一致が開かれるからです。 UNICODE v8には、120,737文字が既に割り当てられています。範囲が17文字を無効にする場合、それは120720の他の可能な文字を受け入れます。これには、多くの印刷不可能な制御文字が含まれる場合があります。

真ん中の文字が取り得る文字の範囲を制限することをお勧めします(そうです、それらはスペースではありませんが、それ以外のものでもかまいません)。

12
user79743
_[[ $var =~ ^b[^[:space:]]+[abcdefghijklmnopqrstuvwxyz]$ ]]
_

_[a-z]_が一致するものはロケールに依存し、通常はnot(のみ)abcdefghijklmnopqrstuvwxyzの1つです。

Perlの_\S_(水平および垂直スペース)は、他の一部の正規表現エンジンでも認識されるようになりました。POSIXおよびbashのEREでは_[^[:space:]]_です。

bashは、システムのregexpライブラリを使用してこれらの正規表現に一致しますが、正規表現に_\S_演算子が含まれるシステム(最近のGNU ones)など)でも、次の理由で機能しません:

_[[ x = \S ]]
_

bashregcomp("S")を呼び出します。

_[[ x = '\S' ]]
_

bashregcomp("\\S")(2つの円記号)を呼び出します。

ただし、bash-3.1を使用する場合、または_shopt -s compat31_とbash-3.1の互換性をオンにすると、次のようになります。

_[[ x = '\S' ]]
_

eREが_\S_をサポートするシステムで機能します(非スペーシング文字と一致します)。

_$ bash -c "[[ x =~ '\S' ]]" || echo no
no
$ bash -O compat31 -c "[[ x =~ '\S' ]]" && echo yes
yes
_

別のオプションは、正規表現を変数に入れることです:

_$ a='\S' bash -c '[[ x =~ $a ]]' && echo yes
yes
_

繰り返しますが、これは正規表現でPerlのような_\S_をサポートするシステムでのみ機能します。

bash固有のコードと同等のPOSIXは次のようになります。

_if expr " $var" : \
        ' b[^[:space:]]\{1,\}[abcdefghijklmnopqrstuvwxyz]$' \
   > /dev/null; then
  printf '%s\n' "$var"
else
  echo none
fi
_

または:

_case $var in
  ([!b]* | *[!abcdefghijklmnopqrstuvwxyz] | *[[:space:]]* | "" | ? | ??)
    echo none;;
  (*) printf '%s\n' "$var"
esac
_
6