Zsh字符串模式匹配删除空格

Zsh字符串模式匹配删除空格

试图解决一个代码高尔夫问题使用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 补全函数所用的语言。

相关内容