在bash/sed中,如何匹配小写字母和大写的SAME字母



我想删除"aA"、"bB"的所有实例。。。输入字符串中的"zZ"。

例如

echo "foObar" |
sed -Ee 's/([a-z])U1//'

应输出"fbar"

但是\U语法在sed表达式的后半部分(替换部分(起作用——它无法在匹配子句中解析。

我很难将匹配的字符转换为大写以便在匹配子句中重用。


如果有人能提出一个可以在sed(或awk(中使用的工作正则表达式,那就太好了。

纯shell中的脚本解决方案也可以(我正在尝试用这种方式解决问题(。

使用PCRE(Perl兼容的正则表达式(也可以,但我不知道它们是如何工作的,所以如果你能提供一个解释来配合你的答案,那就太好了。

不幸的是,我使用的机器上没有安装perl或python。

您可以使用以下perl解决方案:

echo "foObar" | perl -pe 's/([a-z])(?!1)(?i:1)//g'

请参阅在线演示。

详细信息

  • ([a-z])-组1:小写ASCII字母
  • (?!1)-如果下一个字符与组1捕获的字符相同,则会导致匹配失败的负前瞻
  • (?i:1)-与第1组捕获的字符相同,但情况不同(由于之前的前瞻性(

-e选项允许您定义编译器要执行的Perl代码,-p选项每次在循环中都会打印$_的内容。点击此处查看更多信息。

这可能对你有用(GNU sed(:

sed -r 's/aA|bB|cC|dD|eE|fF|gG|hH|iI|jJ|kK|lL|mM|nN|oO|pP|qQ|rR|sS|tT|uU|vV|wW|xX|yY|zZ//g' file

程序化解决方案:

sed 's/[[:lower:]][[:upper:]]/n&/g;s/n(.)1//ig;s/n//g' file

这将标记所有的小写字符对,后跟一个带有前一换行符的大写字符。然后完全移除这样的标记和通过反向引用匹配的对,而不管大小写。删除任何其他换行符,从而保留不相同的对。

这是一个详细的awk解决方案,因为OP没有可用的perlpython

echo "foObar" |
awk -v ORS= -v FS='' '{
for (i=2; i<=NF; i++) {
if ($(i-1) == tolower($i) && $i ~ /[A-Z]/ && $(i-1) ~ /[a-z]/) {
i++
continue
}
print $(i-1)
}
print $(i-1)
}'

fbar

有一个简单的lex,

%option main 8bit
#include <ctype.h>
%%
[[:lower:]][[:upper:]] if ( toupper(yytext[0]) != yytext[1] ) ECHO;

(这是#include之前的一个选项卡,markdown会丢失这些选项卡(。只需将其放入例如that.l,然后放入make that。Easy peasy lex是您工具包中的一个很好的补充。

注意:根据OP的反馈,这个解决方案(毫不奇怪(很慢:
"不幸的是,由于多次通过,速度相当慢。">


如果有一个您知道永远不会出现在输入中的字符序列,
您可以使用sed:使用三阶段替换来实现这一点

echo 'foObar foobAr' | sed -E -e 's/([a-z])([A-Z])/KEYWORD1l2/g' -e 's/KEYWORD(.)1//g' -e 's/KEYWORD(.)(.)/1u2/g'

给您:fbar foobAr

更换阶段说明:

  • 查找后面跟着ANY大写字母的小写字母,并将它们替换为两个小写字母,在它们前面加上KEYWORDfoObar foobAr->fKEYWORDoobar fooKEYWORDbar
  • 删除后面跟有两个相同字符的KEYWORD(现在都是小写,所以后面的引用有效(fKEYWORDoobar fooKEYWORDbar->fbar fooKEYWORDbar
  • 从输出中去除剩余的²KEYWORD,并将其后面的第二个字符转换回原始的大写版本fbar fooKEYWORDbar->fbar foobAr

在本例中,我使用KEYWORD进行演示。单个字符或至少更短的字符序列会更好/更快。只要确保选择一些不可能出现在输入中的内容
²剩下的情况是字母的小写版本不相同,所以我们必须将它们恢复到原始状态

最新更新