我有一个简单的正则表达式,可以为双引号中包含的任何分号创建组匹配。我试图在Mac OS X上使用sed用'SEMICOLO'替换分号...但是,它不起作用..:/
这是我试图使用的命令:
sed -i.bu "s|.*?(;).*?|SEMICOLON|g" output/html/index.html
结果是没有任何东西匹配,也没有任何东西被替换。
期望的行为:
输入
"The man sat; the man cried;" cats; dogs;
输出
"The man satSEMICOLON the man criedSEMICOLON"
cats; dogs;
更新:
谢谢大家的帮助。所以我的例子并不是很好。我真的需要把一个javascript文件压缩到一行,并确保每个js语句都有自己的行。问题是javascript主要是翻译文本,所以试图制作一个简单的正则表达式,在每个;
之后插入换行很困难,因为如果分号在引号中,我显然不希望添加换行符。
长话短说......我意识到我正在尝试重新发明轮子,并决定使用js-beautify
来pretty print
文件。它做的比我需要的多一点......但它现在是最好的解决方案。
再次感谢!
答案 0 :(得分:2)
让我们将其作为测试文件:
$ cat file
"The man sat; the man cried;" cats; dogs;
1; 2; "man;"; 3; ";dog";
尝试使用此sed命令:
$ sed -E ':a; s/^(([^"]*"[^"]*")*[^"]*"[^"]*);/\1SEMICOLON/; ta' file
"The man satSEMICOLON the man criedSEMICOLON" cats; dogs;
1; 2; "manSEMICOLON"; 3; "SEMICOLONdog";
工作原理:
:a
这会创建一个我们稍后可以参考的标签a
。
s/^(([^"]*"[^"]*")*[^"]*"[^"]*);/\1SEMICOLON/
这将替换SEMICOLON中双引号内的最后一个;
。让我们更详细地看一下^(([^"]*"[^"]*")*[^"]*"[^"]*);
:
^
匹配字符串的开头。
([^"]*"[^"]*")*
从该行的开头匹配任意数量的完整引用字符串。
因为,在sed中,正则表达式是贪心(更确切地说,最左边最长),这将尝试匹配尽可能多的完整引用字符串。
[^"]*"[^"]*;
匹配完整引用字符串后面的任何非引号(如上所示),跟随下一个引号字符,后跟任意数量的非引号字符,后跟;
由于上述正则表达式减去最终;
本身就在parens中,因此将其保存为组1.我们将匹配的文本替换为组1,然后替换为SEMICOLON。
ta
如果最后一个命令导致替换(换句话说,我们发现需要替换;
),则跳回标签a
并重复。
让我们考虑一下:
sed "s|.*?(;).*?|SEMICOLON|g"
在Python和其他地方,.*?
是非贪婪的匹配。然而,Sed没有这样的概念。就此而言,默认情况下,sed使用基本正则表达式(BRE),其中?
仅表示文字问号。
另外,将sed命令放在双引号中会有麻烦,因为这会邀请shell修改它。
因此,由于BRE已经过时,让我们(1)使用-E
开关切换到扩展正则表达式(ERE),(2)将命令放在单引号中,以及(3)将.*?
更改为.*
:
$ sed -E 's|.*(;).*|SEMICOLON|g' file
SEMICOLON
(兼容性说明:如果您使用的是非常旧的Linux系统,则可能需要将-E
替换为-r
。)
.*(;).*
匹配行上最后一个分号的所有内容,后跟分号,后跟最后一个分号后面的内容。换句话说,如果该行包含分号,则.*(;).*
匹配整行。这就是为什么输出只是SEMICOLON
。
此外,(;)
匹配分号并将其保存在组1中。由于我们从不在任何地方使用组1,因此这对我们没有任何作用。我们会得到相同的结果:
$ sed -E 's|.*;.*|SEMICOLON|g' file
SEMICOLON
如果我们移除.*
,则会替换每个;
:
$ sed -E 's|;|SEMICOLON|g' file
"The man satSEMICOLON the man criedSEMICOLON" catsSEMICOLON dogsSEMICOLON
如果我们想要替换第一个引用字符串中的最后一个;
,我们可以使用:
$ sed -E 's|^([^"]*"[^"]*);|\1SEMICOLON|g' file
"The man sat; the man criedSEMICOLON" cats; dogs;
如果我们想要替换该行上任何带引号的字符串中的所有;
,那么我们将返回顶部的命令。
让我们考虑一个跨越2行的字符串的测试文件:
$ cat file2
"man;" cat "dog
;"; ";man";
如果你有GNU sed:
$ sed -Ez ':a; s/^(([^"]*"[^"]*")*[^"]*"[^"]*);/\1SEMICOLON/; ta' file2
"manSEMICOLON" cat "dog
SEMICOLON"; "SEMICOLONman";
一般来说任何POSIX sed:
$ sed -E 'H;1h;$!d;x; :a; s/^(([^"]*"[^"]*")*[^"]*"[^"]*);/\1SEMICOLON/; ta' file2
"manSEMICOLON" cat "dog
SEMICOLON"; "SEMICOLONman";
答案 1 :(得分:1)
sed是简单的s / old / new就是全部。有任何awk:
$ awk 'match($0,/"[^"]+"/) {
str = substr($0,RSTART,RLENGTH)
gsub(/;/,"SEMICOLON",str)
$0 = substr($0,1,RSTART-1) str substr($0,RSTART+RLENGTH)
} 1' file
"The man satSEMICOLON the man criedSEMICOLON" cats; dogs;
假设您实际上希望引用字符串中的所有分号都以相同的方式处理。如果没有,无论你想做什么都是一个简单的调整,例如如果您希望删除cried
后的最后一个分号,而不是如示例输出中所示替换:
$ awk 'match($0,/"[^"]+"/) {
str = substr($0,RSTART+1,RLENGTH-2)
sub(/;$/,"",str)
gsub(/;/,"SEMICOLON",str)
$0 = substr($0,1,RSTART) str substr($0,RSTART+RLENGTH-1)
} 1' file
"The man satSEMICOLON the man cried" cats; dogs;