我的代码中包含以下行:

INCORRECT_EMAIL_MOBILE_COMBINATION("incorrect_email_mobile_combination");


当我尝试在可视模式下使用空格替换下划线(使用:'<,'>s/_/ /g)时,vim替换该行中的所有下划线。

如何替换引号内的下划线?

评论

:s在行范围内工作,因此替代的最小单位将是单行而不是其一部分。

到目前为止,我已经在该线程上获得了一些出色的答案!非常感谢大家:)

#1 楼

可以将其视为多级或嵌套搜索的搜索替换。也就是说,首先需要匹配行的一部分(在这种情况下,用引号引起来的字符串)。然后,您需要匹配该字符串的一部分并对其进行替换(为我们加下划线)。

基本正则表达式并不是真的要处理嵌套搜索(有些方法通常很复杂,具体取决于regex变体)。幸运的是,Vim有一个称为子替换表达式的东西,它通常用于解决这些问题:

:s/"\zs[^"]\+\ze"/\=substitute(submatch(0), '_', ' ', 'g')/


在搜索部分,我们识别引用的字符串然后分隔文本从\zs ... \ze对的报价中得出。 IOW,匹配的文本是双引号内的字符串。



":匹配开头的dub-quote

\zs:在此之前的任何内容不包含在替换中

[^"]\+:匹配一个或多个不包含双引号的字符

\ze:此后的任何内容都不包含在替换中

":匹配(结束)dub-quote

在替换部分,我们使用特殊的运算符\=,该运算符告诉Vim将后面的所有内容都视为表达式,对其求值,然后将结果用作替换

具体来说,我们对由substitute()返回的文本执行submatch(0),这是完整的匹配字符串。其他参数应该很容易解释,但这是函数规范:

substitute({expression}, {pattern}, {substitution}, {flags})


返回值和替换文本是我们想要的:字符串之间引号,但下划线处有空格。


将火箭发射器带到刀战中吗?一些人认为这太复杂了。尽管我不会将其用于一次性编辑一两行,但非欧几里得几何很复杂。为此,您只需要足够的正则表达式和\zs .. \ze即可匹配您要应用替换的行的部分。然后...


在模式中键入
键入或粘贴以下内容:/\=substitute(submatch(0), '', '', 'g')/

用替换和替换文本填充参数2和3


奖金材料

冒着与最后一节相抵触的危险...

因为对此似乎有些兴趣我认为我会在上面添加几个变体。我们都喜欢例子。

不使用\ zs或\ ze

进行求解在原始解决方案中,我使用Vim专用的\zs .. \ze令牌对,因为知道如何使用它们有很大的灵活性(关于子替换表达式,通常来说,在Vim中使用正则表达式时)。实际上,尽管特定于OP的情况不需要它们...

 s/"[^"]\+"/\=substitute(submatch(0), '_', ' ', 'g')/


我们只在匹配的字符串中包含引号,这很好,因为替换仅影响下划线。

一个稍微棘手的问题在双引号内使用下划线,但仅在双引号的两侧都带有下划线字符。所以我们最后要......

INCORRECT_EMAIL_MOBILE_COMBINATION("_incorrect_email_mobile_combination_");


是的,\zs .. \ze在这里会再次派上用场,但让我们假装我们需要一个可移植的正则表达式...

解决方案:

INCORRECT_EMAIL_MOBILE_COMBINATION("_incorrect email mobile combination_");


首先,我们将要修改的字符串部分包装到捕获组\(..\)中。这使我们在使用submatch(1)(返回第一个捕获组中包含的字符串)而不是submatch(0)(返回整个匹配的字符串)进行替换时,可以将字符串与引号和外部下划线隔开。

当然,如果我们停止在substitute()调用,我们将失去双引号-下划线对。但是我们只需将它们单引号并使用串联运算符(.)即可将它们按字面意义插入到子替换表达式中...解决了问题。好的,但是如果周围的字符没有固定怎么办?假设引号可以是单引号,也可以是双引号。 br />切换到非常魔幻的模式(['"]_),因此该图案更易于阅读...

s/"_\([^"]\+\)_"/\='"_' . substitute(submatch(1), '_', ' ', 'g') . '_"'/


评论


您确实有一点要很好地学习正则表达式,并且可以全面解决该问题,但是我倾向于发现这种方法过于复杂,以至于在编辑时无法使用。虽然确实适合于插件或映射,但对于这种简单的事情(或在编辑文件时实际遇到的问题的99%),我不建议使用这种方法。对于这种情况,我认为\%V匹配是最简单的。

–filbranden♦
19年7月23日在11:57

如果是一次性编辑,则不建议使用。如果您不熟悉正则表达式或对正则表达式过敏,则可能要远离。除此之外,我真的没有这个想法是非常复杂的,应该避免。使用正则表达式隔离目标文本。之后,替换部分几乎完全固定,文本不变。最坏的情况是,如果您还没有完全将其包裹住,则可以选择一个可以复制/粘贴的位置:/ \ = substitute(submatch(0),'','','g')/。剩下的就是填写您已经知道的参数2和3,因为这是您要解决的问题。

– B层
19年7月23日在16:17

#2 楼

既然您提到了可视模式...您还可以使用\%V匹配仅在当前可视选择中进行匹配(如果不在可视模式下,则为最后一个)。相同的命令,但进行了最小的修改:

:'<,'>s/\%V_/ /g


假设您对带引号的字符串有一个视觉选择,您想在其中替换下划线。

从技术上讲,上面的代码还会在选择项的末尾匹配一个下划线,因为\%V是一个零宽度的匹配项,而其本身仅在选择项之内匹配,因此下划线可能紧随其后。对于这种情况很重要的情况,您可以在模式的末尾添加另一个\%V,以确保整个模式都在选择范围内。

:'<,'>s/\%V_\%V/ /g


我倾向于找到\%V匹配非常有用,因为它使快速修改\%V命令使其仅在选择区域内工作非常容易,而不必更改使用普通模式命令或使用带有函数的表达式作为替换的方法。

评论


看起来像ascii表情符号的搜索模式的奖励积分??? 😂或\\%V _ \%V /

–filbranden♦
19年7月23日在11:48

真好!非常方便。没有接受的答案那么复杂!谢谢,请接受我的支持!

– Doktor OSwaldo
19年7月24日在13:06

#3 楼


如何只在引号内替换下划线?


我认为可以在第一个引号后替换所有下划线。

然后,您可以执行以下操作:

:'<,'>normal f"f_r ,.,.,.,.,.,.,.


即,将f放在引号中,然后将f放在下划线下,然后将r放在空格处,然后重复查找/替换直到足够(甚至更多)为止。

请注意,由于视觉模式,'<'>是自动添加的,因此您不必自己键入它们。

当然,您可以根据需要修改它以使用寄存器。

,此解决方案可能有点麻烦,但我认为它比研究和调试正则表达式更容易这样的例行任务。

评论


但是,如果您“研究和调试正则表达式”,那么一段时间后它们很容易,您不再需要学习和调试它们。或者,您通常可以避免使用它们,并在余生中进行研究和调试。 ;)

– B层
19年7月23日在7:11

@BLayer坦白地说,在这种情况下,仅使用(c)onfirmation标志和:s命令一起是最快的方法。正则表达式看起来像是瞄准麻雀的大炮。

–马特
19年7月23日在7:21

如果他们不愿意在这里提出问题,您是否真的认为他们只需要这样做一次?大炮?也许是那种可以从盖帽枪上发射纸条的小玩具(对我和其他对正则表达式感到满意的人)。

– B层
19年7月23日在7:29

我的最后一条评论听起来不应该听起来有些刺耳,但我意识到事实是可以解释的……这让我很烦。仅供参考...我很冷。 ;)

– B层
19年7月23日在20:39



@BLayer Me也;)Vim只是一个问题:它比显微镜还复杂,但是我们通常用它来打钉子(以编辑纯文本文件)。因此,每次必须不确定是将其当作显微镜还是锤子来抓。但是,平均而言,锤子更实用;)

–马特
19年7月24日在3:09

#4 楼

您也可以只匹配大写字符:

:s/\L\zs_//g


,也可以匹配列号:

/\%>3\%<8


在第3列和第8列之间匹配

#5 楼

这是没有人提及的另一种方法。首先,请注意,在您的示例中,“在引号内”等同于“在第一引号后”。

因此,您可以运行以下替换:

使用正则表达式稍微简单一些的替代版本是:

:'<,'>s/\v(".*)@<=_/ /g
 '<,'>                   # In the visual selection
      s/                 # substitute
        \v               # using "very magic" (this just means we don't need
                         # as many backslash escapes)
                  _      # match any underscore
               @<=       # that follows
          (   )          # a group containing
           "             # a quote
            .*           # followed by anything
                   / /   # replacing it with a space.
                      g  # globally within each line


请注意,这只会替换行中的最后一个下划线,即使您使用g标志(因为该表达式只能与引号匹配一次)。因此,要替换可视区域中的其余下划线,可以通过键入以下命令多次重复替换:次。您可以根据需要增加计数。