我想删除"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没有可用的perl
或python
:
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大写字母的小写字母,并将它们替换为两个小写字母,在它们前面加上KEYWORD
foObar foobAr
->fKEYWORDoobar fooKEYWORDbar
- 删除后面跟有两个相同字符的KEYWORD(现在都是小写,所以后面的引用有效(
fKEYWORDoobar fooKEYWORDbar
->fbar fooKEYWORDbar
- 从输出中去除剩余的²KEYWORD,并将其后面的第二个字符转换回原始的大写版本
fbar fooKEYWORDbar
->fbar foobAr
在本例中,我使用KEYWORD
进行演示。单个字符或至少更短的字符序列会更好/更快。只要确保选择一些不可能出现在输入中的内容
²剩下的情况是字母的小写版本不相同,所以我们必须将它们恢复到原始状态