试图解决一个代码高尔夫问题使用zsh
,但我的正则表达式无法正常工作。
要求
给定输入 string ,删除紧邻任何字符$1
左侧的所有空格。!
例子:
Input ($1) Expected Result:
" ! a! !b c!d !" => "! a!!b c!d!"
"a !" => "a!"
"! a" => "! a"
"! ! !" => "!!!"
"! " => "! "
我想要一个使用的解决方案zsh
仅内置,这是我能得到的最接近的:
<<<${(S)1// *!/!}
很遗憾 - 在线尝试-- 这导致
!!!b!d!
! a
!!!
!
正如你所看到的,第一条线已经被比赛过度热情地破坏了*
。 zsh 文档(指南第 5.9.2 和 5.9.3 条)在这一点上相当令人困惑。
优先+
级运算符也不起作用:(<<<${(S)1//+( )!/!}
答案1
这不是通常的正则表达式语法中的正则表达式。这是一个通配符模式。 Sh 通配符模式的表现力不如正则表达式。 Ksh、bash 和 zsh 具有与正则表达式一样具有表达能力的通配符模式,但语法不同。也可以看看为什么我的正则表达式在 X 中有效但在 Y 中无效?
在 zsh 中执行此操作的正常方法是打开extended_glob
选项(几乎每个人都一直这样做)并使用#
通配符它匹配任意数量的前面的内容(就像*
通常的正则表达式语法一样)。
setopt extended_glob
no_spaces_before_bang=${original_string// #!/!}
您的尝试失败有两个原因。首先,*
通配符模式意味着“任何字符序列”。其次,非贪婪匹配会达不到目的:它会导致没有空间被匹配。
在 ksh、bash aftershopt -s extglob
和 zsh after 中setopt ksh_glob
,您可以使用*( )
来匹配零个或多个空格,或者+( )
匹配一个或多个空格。要么在这里做。
对于正常使用,您只需打开extended_glob
。对于代码高尔夫来说,这是一个相当高的代价。也许你可以将 space-bang 缩小为循环中的 bang:repeat $#a a=${a/ !/!}
。或者您可以进入“extended_glob
打开的 zsh”类别,这是编写 zsh 补全函数所用的语言。