awk、sed或vim正则表达式

4
我正在寻找添加一个字符串到现有字符串的最佳方式,同时我不想替换整个字符串。
self.fields_desc.append(BitField("foo", 0x3, 4))

应该被替换为:

self.fields_desc.append(BitField("foo" + str(self.__class__.i), 0x3, 4))

使用哪个工具可以让我以最少的麻烦来完成这个任务?在vim中,我可以这样做:
:%s/self.fields_desc.append(BitField("[a-zA-Z0-9]*", 0x[0-9]*, [0-9]*))/self.fields_desc.append(BitField("foo" + str(self.__class__.i), 0x3, 4))/g

但我不知道如何告诉vim不要替换我写的正则表达式。你能帮我一下吗?

2个回答

5

使用捕获组(注意在“(”和“)”之前的“ \ ”,以及“ \ 1”,“ \ 2”等):

:%s/self\.fields_desc\.append(BitField(\("[a-zA-Z0-9]*"\), \(0x[0-9]\+\), \([0-9]\+\)))/self.fields_desc.append(BitField(\1 + str(self.__class__.i), \2, \3))/g

变更:

self.fields_desc.append(BitField("foo", 0x3, 4))
self.fields_desc.append(BitField("test", 0x5, 3))

to

self.fields_desc.append(BitField("foo" + str(self.__class__.i), 0x3, 4))
self.fields_desc.append(BitField("test" + str(self.__class__.i), 0x5, 3))

注意:
1. 我已经转义了“.”,因为“.”匹配任何字符(除换行符外),而您需要一个字面上的“.”字符。 2. 我已经将“*”替换为“+”,用于数字匹配:我怀疑您想匹配self.fields_desc.append(BitField("foo", 0x,)等。 3. 如果您不确定间距是否正确,即您不总是使用self.fields_desc.append(BitField("foo", 0x3...,而有时使用self.fields_desc.append(BitField("foo",0x3self.fields_desc.append(BitField("foo", 0x3,那么在空格字符后面添加一个“*”。虽然我建议您标准化代码。
请参见正则表达式分组正则表达式“点”
正如sidyll所说,最好学习使用内置字符类“\d”、“\w”(请参见简写字符类)等。
:%s/self\.fields_desc\.append(BitField(\("\w*"\), \(0x\d\+\), \(\d\+\)))/self.fields_desc.append(BitField(\1 + str(self.__class__.i), \2, \3))/g

这样做既简洁易读,也能让读者更容易理解。否则,读者会认为你有某种特殊的原因来定义自己的字符类(即,他们会读两遍以确保其中没有未知的字符)。


1
很少有我会点踩,但我忍不住:为什么要分组?为什么使用 [0-9] 而不是 \d?为什么不使用零宽度匹配? - sidyll
1
@sidyll: 因为分组更容易理解,特别是对于以前不知道它的人来说,而且它更接近他们原始的正则表达式。坦率地说,因为你不喜欢风格,就对一个可行的答案进行投票反对,这样做相当不雅。你提到了转义'.'的相关点,但其余部分都有些荒谬(尤其是对于一次性的vim正则表达式)。 - jkerian
1
这并不是关于风格的问题,而是关于浪费资源。其中之一是打字,另一种是用于分组的内存。我知道这是一个“单次使用”的丢弃物,但像字符类或零宽匹配这样的东西真的很重要;所以这也不是一个复杂化的问题。如果你在像这个案例这样简单的情况下学习这些内容,即使你花一点时间阅读帮助文件,到了开发更复杂的表达式时,你也会获得胜利。 - sidyll
我现在已经更新了这个程序,使用标准字符类。我没有提到零宽断言,因为我认为这可能会更加混淆,尽管我确实引用了你的答案,所以希望有兴趣的人会去看一下(并且点赞)。你绝对是正确的,我不应该给出这样一个被修改过的回答。 - MGwynne

1
请避免不必要的匹配和替换。使用内置字符类,并转义那些点。这里没有必要对事物进行分组。
:%s/self\.fields_desc\.append(BitField("\w*"\zs\ze, 0x\d, \d))/ + str(self.__class__.i)

你可能不需要使用 g 标志,我怀疑同一行中不会出现两个。

请参阅 :h \zs:h \ze


不错!我不知道\zs\ze。希望我能收藏一个答案:( - MGwynne
1
@MGwynne:嗯,Vim正则表达式引擎和Perl的一样强大,有时甚至更强,但表示方式不同。我知道Perl有一个类似于\zs\k,但不确定它是否有类似于\ze的灵活查找。我不认为POSIX包括这些(不确定)。相当方便,对吧?而且易于使用。顺便说一句,你的答案做得很好,绝对是那些值得3票的精美参考之一,但我只能给一票。 - sidyll
1
@MGwynne:也许我没有表述清楚,但是是的,\zs\ze就是这样做的。它们就像标记一样,用于匹配,\z表示开始,s表示开始,e表示结束。 - sidyll
确实非常有趣!让我想深入研究各种正则表达式引擎的高级功能。但是当一些简单的系统不支持它们时,我会感到很烦恼 :( - MGwynne
从vim文档和您的解释中可以清楚地看出 :)我只是更多地考虑底层实现。 我猜\zs\ze没有与向前/向后查找相同的限制(即,向前/向后查找需要具有恒定的大小),因为\zs\ze的零宽断言始终延伸到字符串的开头和结尾(而look-ahead等可以出现在任何地方)? 是否有更多关于实现细节的参考资料? - MGwynne
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接