任何非空白正则表达式

任何非空白正则表达式

我试图将字符串与 bash 上 if 语句内的正则表达式进行匹配。代码如下:

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

匹配应该是一个以“b”开头,后跟一个或多个非空白字符并以字母 az 结尾的字符串。我可以匹配字符串的开头和结尾,但 \S 无法匹配非空白字符。先谢谢您的帮助。

答案1

在非 GNU 系统中,以下内容解释了\S失败的原因:

\S是 PCRE(Perl 兼容正则表达式)的一部分。它不属于BRE(基本正则表达式)或者ERE(扩展正则表达式)用于贝壳。

=~双括号测试中的bash 运算符[[使用 ERE。

在 ERE 中唯一具有特殊含义的字符(与任何普通字符相反)是.[\()*+?{|^$。没有S那么特别。您需要从更基本的元素构建正则表达式:

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

哪里的括号表达式[^[:space:]] 相当于\SPCRE 表达式:

默认\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) 没有空格(在当前语言环境中)则
  • 检查它是否以 a 开头并以(在 C 语言环境中)b结尾。a-z

请注意,这两个测试都是在正范围(而不是“非”范围)上完成的。原因是否定几个字符会产生更多可能的匹配。 UNICODE v8 已分配 120,737 个字符。如果某个范围否定 17 个字符,则它接受 120720 个其他可能的字符,其中可能包括许多不可打印的控制字符。

限制中间字符可以具有的字符范围应该是一个好主意(是的,这些字符不会是空格,但可能是其他任何字符)。

答案2

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

匹配的内容[a-z]取决于区域设置,通常是不是(仅)其中之一abcdefghijklmnopqrstuvwxyz

perl\S(水平和垂直空格)现在也被其他一些正则表达式引擎识别,位于[^[:space:]]POSIX 和 bash 的 ERE 中。

bash使用系统的正则表达式库来匹配这些正则表达式,但即使在正则表达式具有运算\S符的系统(例如最近的 GNU 系统)上,这也不起作用,因为在:

[[ x = \S ]]

bash调用regcomp("S")并与:

[[ x = '\S' ]]

bash调用regcomp("\\S")(两个反斜杠)。

但是,使用 bash-3.1 或者如果您使用 启用 bash-3.1 兼容性shopt -s compat31,则:

[[ 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

\S同样,这只适用于在正则表达式中支持类似 perl 的系统。

与该特定代码等效的 POSIXbash是:

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

答案3

概括

# match any non-whitespace char--works in bash and `grep` too
[^\r\n\t\f\v ]

细节

匹配(任何非空白字符)显然在or或类似的\S正则表达式中不起作用。因此,不要使用它来匹配一个或多个出现的任何非空白字符:bashgrep

# INSTEAD OF THESE (which do NOT work in bash or `grep`)

# match one or more non-whitespace chars
\S+
# or (same thing)
[\S]+

...用这个:

如何匹配bashand中的所有非空白字符grep

# match one or more non-whitespace chars (DOES work in bash and `grep`!)
[^\r\n\t\f\v ]+

我从那里学到了这一点https://regex101.com/。点击这里:https://regex101.com/r/kM041K/1,在屏幕右侧的“说明”部分下,您将看到:

\S匹配任何非空白字符(相当于[^\r\n\t\f\v ]

因此,如果对任何正则表达式有疑问,请访问该网站并查看其内容。

相关内容