匹配逗号分隔数字的全局模式

匹配逗号分隔数字的全局模式

我想编写一个全局模式来匹配以逗号分隔的数字。图案会是什么样子?

这里有些例子

5
5,8,13

已从以下内容开始,但存在一些问题,因为我没有得到匹配。

var="8,13,21"
echo "var: $var"
if [[ "$var" == ^*([[:digit:]])+(,+[[:digit:]])$ ]]; then
  echo "match"
fi

答案1

bash 手册描述了[[ expression ]]语法:

==使用和运算符时!=,运算符右侧的字符串被视为模式,并根据模式匹配下描述的规则进行匹配,就像 extglob 启用了 shell 选项一样。

这里的 shell选项extglob表示 ksh 风格的扩展 glob,即:

  ?(pattern-list)
         Matches zero or one occurrence of the given patterns
  *(pattern-list)
         Matches zero or more occurrences of the given patterns
  +(pattern-list)
         Matches one or more occurrences of the given patterns
  @(pattern-list)
         Matches one of the given patterns
  !(pattern-list)
         Matches anything except one of the given patterns

我怀疑+[[:digit:]]是试图匹配 1 个或多个数字 - 这需要是+([[:digit:]]).所以逗号后跟 1 个或多个数字,所有零次或多次都是*(,+([[:digit:]]),最后

+([[:digit:]])*(,+([[:digit:]]))

匹配 1 个或多个数字,后跟零个或多个逗号分隔的一个或多个数字以形成逗号分隔列表。

请注意,glob 表达式不使用^$锚点 - 它们始终是整行,如果您想要部分匹配,则需要用*通配符将表达式括起来。


1 这是自 bash 4.1 以来的新内容。在旧版本中,您需要显式地shopt -s extglob让那些扩展的全局运算符在内部可用,就像在外部一样[[...]]

答案2

请注意,您使用的语法看起来像是通配符和正则表达式语法的混合。

如果你想使用 Bash 的 RegEx 匹配(如上所述在评论中),那么您需要使用=~比较运算符。在这种情况下,测试构造的正确语法是

if [[ "$var" =~ ^([[:digit:]])+(,[[:digit:]]+)*$ ]]; then
...

请注意,这与您在几个方面展示的尝试不同:

  • 在您当前的尝试中,,+[[:digit:]]将匹配“一个或多个逗号,后跟一位数字”。
  • RegEx开头*的 似乎是杂散的 - 只要您不打算匹配文字*,它要么是错误的(*在 RegEx 中意味着“零个或多个前面的字符”,而不是“任何可能的字符组合”)或多余的(如果你想匹配$.*,你也可以去掉锚并简单地声明([[:digit:]])+(,+[[:digit:]])$)。

另一方面,如果您实际上想使用“扩展通配符”语法(在运算符[[ ... ]]的构造中确实默认接受该语法==),那么

  • ^锚点 (和)的使用$是错误的 - 它们仅对正则表达式有效,而不是通配语法的一部分,即使是扩展形式也是如此。它们也不是必需的,因为默认情况下,全局模式适用于整个字符串。
  • 此外,每一个前面有“重复说明符”(例如*+)的项目需要放在括号中,因此语句中缺少一组括号+[[:digit:]]

所以在这种情况下,你的匹配 glob 需要看起来像

if [[ "$var" == +([[:digit:]])*(,+([[:digit:]])) ]]; then echo "match"; fi

答案3

为了完整起见,如果您想sh在语句中使用标准通配符case[[...]]是 kshism)来做到这一点,您需要采取相反的方法:

case $var in
  ('' | *[!,0123456789]* | *, | ,* | *,,* ) echo WRONG;;
  (*) echo RIGHT;;
esac

标准 glob 模式中没有 ERE 的等效项+(与 zsh##或 ksh相同)。+(...)

但是,您可以借助以下命令进行正则表达式匹配¶ awk

rematch() { awk -- 'BEGIN{exit(ARGV[1] !~ ARGV[2])}' "$@"; }

if rematch ",$var" '^(,[0123456789]+)+$'; then
  echo RIGHT
else
  echo WRONG
fi

1 在 中awk,您会得到标准扩展正则表达式的一个变体,它也可以理解(或意味着理解,但并非全部以这种方式使用)ANSI C 转义序列,例如\n, \t, \b(用于退格,而不是 perl 样式的单词边界)。

相关内容