在我的 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
通配符模式的超集。语法还受kshglob
和extendedglob
选项的影响。它${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
)。aaab
aab
ab
b