我可以在 zsh 参数扩展中使用什么样的模式?

我可以在 zsh 参数扩展中使用什么样的模式?

在我的 zsh shell 脚本中,我regexp-replace nname "_{2,}" "_"成功地将多个“_”减少为一个,但是当我尝试${nname//_{2,}/'_'}zsh 时,它似乎与该模式不匹配。

man zshexpn是。不清楚。它提到了通配模式,但显然还有其他 POSIX 1003.2 正则表达式,例如在${name//[^[:alnum:]]/"_"} 我的脚本中工作正常。

动机

我正在寻找相当于的参数扩展

regexp-replace nname "[^[:alnum:]]" "_"
regexp-replace nname "_{2,}" "_"
regexp-replace nname "_+$" ""
regexp-replace nname "^_+" ""

桀骜

zsh --version
zsh 5.7.1 (x86_64-apple-darwin19.0)

答案1

${var//pattern/replacement}正在使用 zsh 通配符模式pattern,与用于的相同文件名生成又名通配符,是sh通配符模式的超集。语法还受kshglobextendedglob选项的影响。它${var//pattern/replacement}最初来自 Korn shell。

我建议启用extendedglob(set -o extendedglob在您的~/.zshrc) 中,它可以为您提供最多的功能(比标准 ERE 更多),但在某些极端情况下会导致向后不兼容。

您会发现它记录在info zsh 'filename generation'

ERE 和扩展 zsh 通配符之间映射的备忘单:

标准sh的:

  • .->?
  • .*->*
  • [...]->[...]

zsh 扩展:

  • *->#
  • +->##
  • {x,y}->(#cx,y)
  • (...|...)->(...|...)

标准 ERE 中不提供一些额外功能:

  • ^pattern(否定)
  • x~y(除了)
  • <12-234>匹配小数范围
  • (#i)不区分大小写的匹配
  • (#a2)近似匹配最多允许 2 个错误。
  • 还有很多

通配符模式是否锚定在主题的开头或结尾取决于使用的运算符。

  • Glob、case模式[[ string = pattern ]]${var:#pattern}都锚定在(f*.txt将匹配foo.txt,而不是Xfoo.txtY
  • ${var#pattern}${var##pattern}锚定在开始处
  • ${var%pattern)${var%%pattern}锚定在末端
  • ${var/pattern/repl}和不是锚定的,但可以通过(start) 或(end)${var//pattern/repl}来实现。${var/#pattern}${var/%pattern}

(#s)并且(#e)也可以用作^/ $(ERE) 或\A/ \z(PCRE) 的等价物。

重复运算符 ( #, ##, *, (#cx,y), <x-y>) 是否贪婪也取决于运算符(贪婪于##, %%, ///不贪婪于#, %),可以通过S参数扩展标志进行更改。

所以对于你的例子:

  • regexp-replace nname "[^[:alnum:]]" "_":${var//[^[:alnum:]]/_}
  • regexp-replace nname "_{2,}" "_":${var//_(#c2,)/_}
  • regexp-replace nname "_+$" "":${var%%_#}${var/%_#}(此处用于#等效*项,您可以使用##等效+项,但在这种情况下不会有任何区别)。
  • regexp-replace nname "^_+" ""${var##_#}或者${var/#_#}

在这里,您可以将它们组合起来${${${var//[^[:alnum:]]##/_}#_}%_}(将非 alnum 序列转换为_并删除最终的前导或尾随_)。

另一种方法可能是提取所有 alnums 序列并将它们与 结合起来_,使用以下 hack:

words=()
: ${var//(#m)[[:alnum:]]##/${words[1+$#words]::=$MATCH}}
var=${(j:_:)words}

regexp-replace[[ $var =~ pattern ]]本身是一个循环调用的自动加载函数。请注意,结果是,它不能与^锚点或单词边界或后视运算符一起正常工作(如果使用该rematchpcre选项)

$ a='aaab'; regexp-replace a '^a' x; echo "$a"
xxxb
$ a='abab'; regexp-replace a '\<ab' '<$MATCH>'; echo $a
<ab><ab>

(在第一个例子中,在该循环中依次与 、 、进行匹配^a)。aaabaababb

相关内容