正则表达式替换:匹配中的多个替换

Posted

技术标签:

【中文标题】正则表达式替换:匹配中的多个替换【英文标题】:Regexp-replace: Multiple replacements within a match 【发布时间】:2012-09-28 16:18:19 【问题描述】:

我正在将我们的 MVC3 项目转换为使用 T4MVC。而且我想替换 java-script 包含也可以与 T4MVC 一起使用。所以我需要更换

"~/Scripts/DataTables/TableTools/TableTools.min.js"
"~/Scripts/jquery-ui-1.8.24.min.js"

进入

Scripts.DataTables.TableTools.TableTools_min_js
Scripts.jquery_ui_1_8_24_min_js

我目前正在使用 Notepad++ 作为正则表达式工具,它使用的是 POSIX 正则表达式。 我可以找到脚本名称并将其替换为这些正则表达式:

查找:\("~/Scripts/(.*)"\)

替换为\(Scripts.\1\)

但我不知道如何将文件名中的点和破折号替换为下划线并将正斜杠替换为点。

我可以用这个检查 js-filename 的名称中是否有点或破折号

 \("~/Scripts/(?=\.*)(?=\-*).*"\)

但是如何替换组内的组?

需要在组内进行非贪婪替换,并且这些替换按顺序进行,因此转换为点的正斜杠之后不会转换为下划线。

这是一个非关键问题,我已经手动完成了所有替换,但我认为我对正则表达式很好,所以这个问题困扰着我!!

附言首选工具是 Notepad++,但任何 POSIX 正则表达式解决方案都可以 -)

p.p.s. Here you can get a sample 要替换的东西 And here is the the target text

【问题讨论】:

您的目标是将一些文本复制到编辑器,让它进行替换,然后再复制回来吗? 是的,差不多。从某处的 Visual Studio 复制,进行替换,复制回 VS。我确定 VS 无法处理,所以必须在其他地方完成。 不使用您正在使用的 VS,但 PowerGUI 控制台使您可以在 Visual Studio 中访问 Powershell 以操作编辑器环境,因此您可以在 VS 中获得漂亮的正则表达式外观。可能值得一看。 哦,太好了!我试试看!我正在使用VS2012。内置的正则表达式搜索替换非常奇怪且不合规。 【参考方案1】:

我只会使用像RegexHero这样的网站

    您可以将代码粘贴到目标字符串框中,然后将(?<=(~/Script).*)[.-](?=(.*"[)]")) 放入Regular Expression 框中,_ 放入Replacement String 框中。

    替换完成后,点击底部的Final String,然后选择Move to target string and start a new expression

    从那里,将(?<=(<script).*)("~/)(?=(.*[)]" ))|(?<=(Url.).*)(")(?=(.*(\)" ))) 粘贴到Regular Expression 框中,并将Replacement String 框留空。

    替换完成后,点击底部的Final String,然后选择Move to target string and start a new expression

    从那里将(?<=(Script).*)[/](?=(.*[)]")) 粘贴到Regular Expression 框中,将. 粘贴到Replacement String 框中。

之后,Final String 框中将包含您要查找的内容。我不确定您可以解析多少文本的上限,但如果这是一个问题,它可能会被分解。我确信可能有更好的方法来做到这一点,但这往往是我处理此类事情的方式。我喜欢这个网站的一个原因是因为我不需要安装任何东西,所以我可以在任何地方快速完成。

编辑 1:根据 cmets,我已将步骤 3 移至步骤 5,并添加了新的步骤 3 和 4。我必须这样做,因为新的步骤 5 将替换 "~/Scripts 中的 "~/Scripts一个.,打破了"~/的删除。我还必须更改第 5 步的代码以说明 Script 开头的更改

【讨论】:

绝对的魔法!感谢您的链接 - 以前从未见过它,但我可以看到它将来会被大量使用!到目前为止,解决方案是最简单的,只有 2 遍。一场胜利! @trailmax 我错过了你的问题吗?您问题中提供的示例行与此解决方案提供的输出不匹配。也许您可以使用 full 行来编辑您的问题示例? @Thell 啊!你说的对。我确实错过了脚本之前的引号和〜。这不是什么大不了的更换。但是使用正则表达式添加另一遍,使其成为三遍。 @Thell 我已将目标文本添加到问题中。尼克,也许你想修改你的答案并添加另一个正则表达式传递来去除额外的引号和波浪号。只为成为绝对的英雄 -) @trailmax 我已经调整了步骤以考虑"~/ 和最后一个"【参考方案2】:

这是一个普通的 Notepad++ 解决方案,但它肯定不是最优雅的解决方案。我设法对文件进行了几次转换。

第一关

.- 替换为_

查找:("~/Scripts[^"]*?)[.-]

替换为:\1_

不幸的是,我找不到匹配.- 的方法,因为它需要后视,Notepad++ 显然不支持。因此,每次执行替换时,只会替换脚本名称中的第一个 .-(因为匹配项不能重叠)。因此,您必须多次运行此替换,直到不再进行替换(在您的示例输入中,这将是 8 次)。

第二遍

/ 替换为.

查找:("~/Scripts[^"]*?)/

替换为:\1.

这与第一遍基本相同,只是字符不同(对于示例文件,您必须这样做 3 次)。按此顺序进行传递可确保没有斜杠以下划线结尾。

第三遍

删除周围的字符。

查找:"~/(Scripts[^"]*?)"

替换为:\1

这现在将匹配仍然被"~/" 包围的所有脚本名称,捕获它们之间的内容并输出。

请注意,通过在前两遍的查找模式中包含周围的字符,可以避免将 . 转换为新格式的字符串。

正如我所说,这不是最方便的方法。特别是,由于必须多次手动执行第一遍和第二遍。但是它仍然可以为大文件节省大量时间,而且我想不出一种方法来获取所有这些文件 - 仅在正确的字符串中 - 一次通过,没有后视功能。当然,我非常欢迎提出改进此解决方案的建议 :)。我希望我至少可以给你(以及任何有类似问题的人)一个起点。

【讨论】:

辛苦了!谢谢。我希望避免多次通过,至少使用相同的正则表达式。但由于缺乏回应,这似乎是不可能的。 好吧,如果你能命名一个你可以使用的 POSIX 正则表达式引擎,它支持正的、可变长度的lookbehinds,我可以尝试找到一个解决方案,每次只使用一次(尽管即使那样,我不确定,是否允许后视重叠) 是的,我没有意识到 notepad++ 不支持所有必需的正则表达式功能。但正如尼克所说,RegexHero 做了所有的前瞻和后瞻。它允许在 2 遍中进行转换。 是的,这就是我想到的后视解决方案。我只是不知道您可以使用支持它们的引擎:)。我也很喜欢python脚本……虽然它需要一个额外的插件【参考方案3】:

如您的问题所示,如果您想使用 N++,请使用 N++ Python 脚本。设置脚本并分配一个快捷键,然后您就拥有了一个只需要打开、修改和保存的单通道解决方案......没有比这更简单的了。

我认为部分问题在于 N++ 不是正则表达式工具并且使用了专用的正则表达式工具 ,甚至是搜索/替换解决方案,有时是必要的。使用用于文本处理和编辑的工具,您可能会在速度和时间价值方面做得更好。

[脚本编辑]:: 已更改以匹配修改后的输入/输出预期。

# Substitute & Replace within matched group.
from Npp import *
import re

def repl(m):
    return "(Scripts." + re.sub( "[-.]", "_", m.group(1) ).replace( "/", "." ) + ")"

editor.pyreplace( '(?:[(].*?Scripts.)(.*?)(?:"?[)])',  repl )
    安装:: 插件 -> 插件管理器 -> Python 脚本 新脚本:: 插件 -> Python 脚本 -> script-name.py 选择目标标签。 运行:: 插件 -> Python 脚本 -> 脚本 -> 脚本名称

[编辑:一个扩展的单行 PythonScript 命令]

由于需要新的 Python 正则表达式模块(我希望能取代 re),我尝试并编译了它以与 N++ PythonScript 插件一起使用,并决定在您的示例集上对其进行测试。

控制台上的两个命令最终在编辑器中得到了正确的结果。

import regex as re
editor.setText( (re.compile( r'(?<=.*Content[(].*)((?<omit>["~]+?([~])[/]|["])|(?<toUnderscore>[-.]+)|(?<toDot>[/]+))+(?=.*[)]".*)' ) ).sub(lambda m: 'omit':'','toDot':'.','toUnderscore':'_'[[ key for key, value in m.groupdict().items() if value != None ][0]], editor.getText() ) )

非常甜蜜!

使用regex 而不是re 真正酷的是我能够在Expresso 中构建表达式并按原样使用它!这允许对其进行详细解释,只需将r'' 字符串部分复制粘贴到 Expresso 中即可。

其中的简写为::

Match a prefix but exclude it from the capture. [.*Content[(].*]
[1]: A numbered capture group. [(?<omit>["~]+?([~])[/]|["])|(?<toUnderscore>[-.]+)|(?<toDot>[/]+)], one or more repetitions
    Select from 3 alternatives
         [omit]: A named capture group. [["~]+?([~])[/]|["]]
             Select from 2 alternatives
                 ["~]+?([~])[/]
                 Any character in this class: ["]
         [toUnderscore]: A named capture group. [[-.]+]
         [toDot]: A named capture group. [[/]+]
Match a suffix but exclude it from the capture. [.*[)]".*]

命令分解相当漂亮,我们告诉 Scintilla 将完整的缓冲区内容设置为已编译的正则表达式替换命令的结果,方法是基本上使用非空组名称的“开关”。

希望 Dave(PythonScript 作者)将正则表达式模块添加到项目的 ExtraPythonLibs 部分。

【讨论】:

是的...N++ Python 脚本太棒了!【参考方案4】:

或者,您可以使用一个脚本来执行此操作,并完全避免复制粘贴和其余的体力劳动。考虑使用以下脚本:

$_.gsub!(%r(?:"~/)?Scripts/([a-z0-9./-]+)"?i) do |i| 
    'Scripts.' + $1.split('/').map  |i| i.gsub(/[.-]/, '_') .join('.')
end

然后像这样运行它:

$ ruby -pi.bak script.rb *.ext

所有带有.ext 扩展名的文件将被就地编辑,原始文件将以.ext.bak 扩展名保存。如果您使用修订控制(并且应该),那么您可以使用一些视觉差异工具轻松查看更改,必要时更正它们并在之后提交。

【讨论】:

这只是一个文件中的一次更改,所以有点矫枉过正。但是 +1 用于引入新工具。不幸的是无法测试 - 没有设置任何 ruby​​ 环境。 当然。我认为学习使用 Ruby、Python 或 Perl 之类的东西来完成这样的任务是件好事。即使是这样的一次性任务,您也会比使用编辑器更快。编辑器通常只提供简单的正则表达式替换,任何与此不同的东西都会变成问题。使用这样的脚本,只需一步即可完成多个文件或其他重复场景的自动化。 是的,我在完全迁移到 Windows 之前使用了 Bash。我本来打算看看 Ruby 一段时间 - 可能刚刚开始 -)

以上是关于正则表达式替换:匹配中的多个替换的主要内容,如果未能解决你的问题,请参考以下文章

一个可以使用多个正则表达式进行多次尝试匹配,并进行替换的Excel VBA自定义函数(UFD)

Java 正则表达式 替换字符串中人名

如何用正则表达式替换多个匹配项/组?

Android怎么用正则表达式替换字符串某些字符?

正则表达式,替换 指定范围内 的 特定字符串

正则表达式如何替换并修改自身的部分内容?