我想从输入字符串中删除“ aA”,“ bB” ...“ zZ”的所有实例。
例如
echo "foObar" |
sed -Ee 's/([a-z])\U\1//'
应输出"fbar"
但是\ U语法在sed表达式的后半部分(替换部分)中起作用-无法在匹配子句中解析。
我很难将匹配的字符转换为大写以在匹配子句中重用。
如果有人建议使用可以在sed(或awk)中使用的正则表达式,那就太好了。
使用纯shell编写脚本解决方案也是可以的(我正在尝试以这种方式解决问题)。
工作PCRE(与Perl兼容的正则表达式)也可以,但是我不知道它们如何工作,因此,如果您能提供一个解释来回答问题,那就太好了。
不幸的是,我没有在使用的机器上安装perl或python。
答案 0 :(得分:3)
您可以使用以下perl解决方案:
echo "foObar" | perl -pe 's/([a-z])(?!\1)(?i:\1)//g'
请参见online demo。
详细信息
([a-z])
-第1组:小写ASCII字母(?!\1)
-如果下一个字符与用组1捕获的字符相同,则负匹配将使匹配失败(?i:\1)
-与第1组捕获的字符相同,但在不同情况下(由于之前的超前查找)。 -e
选项允许您定义要由编译器执行的Perl代码,而-p
选项始终在循环中每次输出$_
的内容。参见more here。
答案 1 :(得分:3)
这可能对您有用(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
这会标记所有成对的小写字符,后跟一个大写字符并带有换行符。然后,将所有由后向引用匹配的标记和配对全部删除,而不管大小写如何。删除所有其他换行符,从而使不相同的对保持不变。
答案 2 :(得分:2)
这是一个详细的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
答案 3 :(得分:1)
注意:根据OP的反馈,此解决方案很慢(毫不奇怪):
“不幸的是,由于多次通过-它使速度变慢。”
sed
使用三阶段替换来完成此操作:
echo 'foObar foobAr' | sed -E -e 's/([a-z])([A-Z])/KEYWORD\1\l\2/g' -e 's/KEYWORD(.)\1//g' -e 's/KEYWORD(.)(.)/\1\u\2/g'
给您:fbar foobAr
替换阶段说明:
foObar foobAr
-> fKEYWORDoobar fooKEYWORDbar
fKEYWORDoobar fooKEYWORDbar
-> fbar fooKEYWORDbar
fbar fooKEYWORDbar
-> fbar foobAr
¹在此示例中,我使用KEYWORD
进行演示。单个字符或至少较短的字符序列会更好/更快。只需确保选择输入中永远不可能出现的内容即可。
²剩余的字母是小写字母 不相同的情况,因此我们必须将它们恢复为原始状态
答案 4 :(得分:1)
有一个简单的词法,
%option main 8bit
#include <ctype.h>
%%
[[:lower:]][[:upper:]] if ( toupper(yytext[0]) != yytext[1] ) ECHO;
(这是#include
之前的标签,降价会丢失这些标签)。只需将其放在例如that.l
,然后make that
。 Easy-peasy lex是您工具包的不错补充。