![多行查找和替换 - Notepad++,正则表达式,从特定行复制文本并在另一行替换](https://linux22.com/image/1524415/%E5%A4%9A%E8%A1%8C%E6%9F%A5%E6%89%BE%E5%92%8C%E6%9B%BF%E6%8D%A2%20-%20Notepad%2B%2B%EF%BC%8C%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%8C%E4%BB%8E%E7%89%B9%E5%AE%9A%E8%A1%8C%E5%A4%8D%E5%88%B6%E6%96%87%E6%9C%AC%E5%B9%B6%E5%9C%A8%E5%8F%A6%E4%B8%80%E8%A1%8C%E6%9B%BF%E6%8D%A2.png)
我在多行查找和替换中面临着一项艰巨的任务(在不同的部分中解释)。
我寻求的解决方案涉及在 Notepad++ 中使用正则表达式以及内置的查找和替换或使用NPP工具桶插入。
这是输入文件的示例摘录:
ALPHA('Hello John')
IGNORE111
IGNORE222
BETA('Hi Mary')
我需要将 Hi Mary(第四行)替换为 Hello John(从第一行获取的内容)。即,第四行中 BETA(' 和 ') 之间的实际内容应该替换为从第一行中 ALPHA(' 和 ') 之间获取的内容。
期望的结果应该是:
ALPHA('Hello John')
IGNORE111
IGNORE222
BETA('Hello John')
我面临的问题是我有 47 个 IFC 文件(每个文件超过 12000 行)。这些文件的第一行有一个程序集名称(每个 IFC 文件都是唯一的),需要使用它来替换所有 47 个 IFC 文件中第 48 行、第 87 行和更多行中的某处内容。它们都遵循特定的模式。您能建议使用正则表达式实现此目的的技巧吗?
说喜欢 - 找到使用(ALPHA\(')(.*)(')(NEW_SYNTAX_I_SEEKING)(BETA\(')(.*)(')
并替换为\1\2\3\4\5\2\7
在哪里
(ALPHA\(')
将成为回头客\1
(.*)
将成为反向引用\2
,它将拆分为 -> Hello John
(')
将成为回头客\3
(NEW_SYNTAX_I'M_SEEKING) 将成为 back ref \4
;这将是我正在寻找的新正则表达式语法,它将获取分布在多行中的内容以及我不想进行任何更改的内容
(BETA\(')
将成为回头客\5
(.*)
将成为 back ref \6
,它将拆分为 -> Hi Mary,因此我们可以使用 back ref \
2 来替换 back ref \6
。
(')
将成为回头客\7
希望我的问题和意图能够得到正确表达。我会非常感激任何帮助。
干杯,JJ
答案1
如果您经常使用文本文件,您一定会喜欢它awk
。
awk -i inplace 'NR==1 && match($0, /.*\('\''(.+)'\''\)/,matches) {name = matches[1]; print $0} /IGNORE/ {print $0} NR>1 && !/IGNORE/ {print gensub (/([\w ]*\('\'').+('\''\))/, "\\1"name"\\2", "1")}' *.txt
解释需要一段时间,首先让我将命令分解为三个部分,每个部分由一个条件和一个命令组成:
NR==1 && match($0, /.*\('\''(.+)'\''\)/,matches) {name = matches[1]; print $0}
这将打印第一行并将您的情况下的程序集名称复制到一个名为的变量中name
。/IGNORE/ {print $0}
如果行与文本匹配IGNORE
,则打印它们。NR>1 && !/IGNORE/ {print gensub (/([\w ]*\('\'').+('\''\))/, "\\1"name"\\2", "1")}
name
使用之前创建的变量对剩余的行执行正则表达式替换。
以下是一些详细信息:
awk
这是一个操作文本文件的工具,或者我推荐perl
。
-i inplace
这意味着原始文件将被编辑(请备份!)。免责声明:我尚无法测试此设置,因为它需要awk
比我已安装的版本更新的版本。
'
该命令是一个字符串,因此它被封装在撇号中。
NR==1
这是一个条件,行号必须是1
。
&&
这意味着“AND”。
match(
这是必须满足的另一个条件:接受 3 个参数的正则表达式匹配函数。
$0
第一个参数:这代表整条线。
/.*\('\''(.+)'\''\)/
第二个参数,正则表达式
matches
第三个参数,存储匹配字符串的变量。
{
如果条件为真,则从这里开始执行操作。
name = matches[1]
该变量name
被创建并且被分配为等于第一个捕获组(与反向引用相同\1
)。
;
分号分隔指令。
print $0
我们也打印第一行。
/IGNORE/
查找包含文本的行IGNORE
。
{print $0}
只需打印出来即可。
NR>1 && !/IGNORE/
条件:除第一行之外的所有行,如果它们不包含文本IGNORE
。
{print
打印替换的结果。
gensub (
执行搜索和替换的函数允许使用反向引用。
/([\w ]*\('\'').+('\''\))/
搜索模式。此处的序列'\''
是插入单个 所需的'
。
"\\1"name"\\2"
替换模式。"\1"
和"\2"
是两个反向引用。
"1"
意味着只有第一个匹配项需要被替换。
'
命令结束awk
。
*.txt
在当前目录中awk
所有带扩展名的文件上运行。.txt
笔记:我知道您问的是如何在 Notepad++ 中执行此操作,但我认为您应该考虑使用命令行工具。原因是图形程序更适合执行一次性操作,但在注释中您指定您希望自动执行工作并一次处理 47 个文件。命令行比图形界面更适合自动化,这就是我的观点。
首先,你需要适用于 Windows 的 gawk (GNU awk)如果你想继续,你可以在 Linux 上工作,或者安装类似 Linux 的环境,例如赛格威。
答案2
确保检查:[ ]. 匹配换行符选项
搜索:(ALPHA(.*?)\).*?)(BETA(.*?)\).*?).*?
替换为:\4\1\3\2\
答案3
所有这些捕获组都是无用的并且会减慢进程,您只需要一个。
- Ctrl+H
- 找什么:
^ALPHA\('(.+?)'\).+?BETA\('\K.+?(?='\))
- 用。。。来代替:
$1
- 查看 环绕
- 查看 正则表达式
- 查看
. matches newline
- Replace all
解释:
^ # beginning of line
ALPHA\(' # literally ALPHA('
(.+?) # group 1, 1 or more any character, not greedy (i.e. Hello John)
'\) # literally ')
.+? # 1 or more any character, not greedy
BETA\(' # literally BETA('
\K # forget all we have seen until this position
.+? # 1 or more any character, not greedy (i.e. Hi Mary)
(?='\)) # positive lookahead, make sure we have ') after
截图(之前):
截图(之后):
答案4
以下答案已编辑 - 当我们有超过 9 个反向引用时,建议使用 $ 而不是 \
利用从论坛收集的信息进行一些调整对我有帮助。
解决方案非常简单(技巧在第 2 步)
- 打开内置查找和替换在记事本++中
- 请务必检查:
[ ] . matches newline option
- 在查找内容中输入:
(ALPHA\(')(.*)('\))(.*)(BETA\(')(.*)('\))
- 在替换为中,输入
$1$2$3$4$5$$2$7
- 根据您的需要,单击“替换”/“全部替换”/“在所有打开的文档中全部替换”。
解释
(ALPHA\(')
将成为回头客$1
(.*)
将成为反向引用$2
,它将拆分为 ->Hello John
('\))
将成为回头客$3
(.*)
将成为返回引用$4
;这将获取跨多行的内容,而我不想进行任何更改(BETA\(')
将成为回头客$5
(.*)
会变成 back ref$6
,它会分裂为 ->Hi Mary
,所以我们可以使用 back ref$2
来替换 back ref$6
。('\))
将成为回头客$7