如何用正则表达式实现文档指定部分的文本替换?

如题,我有一批文档,每个文档开头都有一段文字,以其中一个为例

---
Tag(s): /I/-/文/学/ /I/7/./1/./2/./0/美/国/文/学/ /I/7/./1/./0/北/美/文/学/ /I/7/./1/./2/./1/./0/诗/歌/、/韵/文/ /I/7/-/美/洲/文/学/ /I/7/./1/./2/./1/./0/2/0/W/a/l/t/-/W/h/i/t/m/a/n/(/1/8/1/9/-/1/8/9/2/)/
---

我的需求是
1.将---之间的tag部分的/批量删除
2.将tag部分的半角空格 替换为/
3.将这部分的.替换为_
4.对这一批文档(大概几千个)批量进行上述处理

目前比较习惯用的文本编辑器有notepad++和emeditor,但只能对整篇文档进行处理,绞尽脑汁也想不到怎么将指定部分的文本替换,但又不“误伤”其他文档内其他文本的的方法,希望有熟悉的朋友能不吝赐教,谢谢谢谢!

首先要说明正则不是万能的,在某些角度下它是有很大局限性的,所以千万不要认为任何查找替换类的问题都可以用正则去解决,或者都适合用正则去解决。也许用脚本分几次去进行处理,效率更高。

然后回到这个问题,先假设你所给出的这段示例没有进行任何精简。

那么我们可以先提取特征,这里有三行文字:

  • 第 1 行是:---
  • 第 2 行是:Tag(s): 开头的文字
  • 第 3 行是:---

上面这些特征是用来识别的,而它本身并不发生改变,这时候可以使用断言。但这时候就又要说到各种编辑器以及各种编程语言,对于正则的支持是不相同的(甚至在语法上都有一定的区别),在有些编辑器或者有些语言下是没有办法使用断言的……

仍然要使用正则的话,可能只好每次只处理一处替换,然后不断重复操作,直至所有需要修改的地方都被修改完成。

所以比较方便的方法还是使用脚本,用正则确定出这三行,然后再把这些内容交给下一步去进行处理,这样能简单好多,效率也能提升好多。

看到个功能,不过我没用过。
2021-09-03_212049

notepad3 可以,但是一次只能替换一处,需要连续执行很多次

写代码解决吧,这样最简单

首先确认这是你要的效果

---
Tag(s):/I-文学/I7_1_2_0美国文学/I7_1_0北美文学/I7_1_2_1_0诗歌、韵文/I7-美洲文学/I7_1_2_1_020Walt-Whitman(1819-1892)
---

然后确认每个Tag(s):都在第二行(不在没事,只不过会跳过修改)

然后下载个AHKV2
https://www.autohotkey.com/download/2.0/
或者直接下载
https://www.autohotkey.com/download/2.0/AutoHotkey_2.0-beta.1.zip
解压里面的AutoHotkeyU64.exe到任意文件夹(比方说桌面)

然后在这个文件夹新建个文件保存下面的代码
然后在脚本最开始的地方设置自己的路径及文件格式
然后拖拽这个脚本文件到AutoHotkeyU64.exe上

最好测试下随便复制几篇到一个文件夹,然后针对这个文件夹测试
脚本是遍历子文件夹的

path := "F:\Documents\Desktop\新建文件夹"  ;文件路径
ext := "txt" ;文件格式

Loop Files path "/*." ext, "R"
{
    FileObj := FileOpen(A_LoopFileFullPath, "r")
    all := FileObj.Read()
    FileObj.Seek(0,0)
    FileObj.ReadLine()
    line := FileObj.ReadLine()
    if !InStr(line,"Tag(s)")
        continue
    line2 := StrReplace(line, "/", "")
    line2 := StrReplace(line2, " ", "/")
    line2 := StrReplace(line2, ".", "_")
    end := StrReplace(all,line, line2)
    FileObj.Close()
    FileDelete(A_LoopFileFullPath)
    FileAppend(end,A_LoopFileFullPath)
    all := line := line2 := end := ""
}
1 个赞

如果不是每个Tag(s):都在第二行 可以试试这个

path := "F:\Documents\Desktop\新建文件夹"  ;文件路径
ext := "txt" ;文件格式

Loop Files path "/*." ext, "R"
{
    FileObj := FileOpen(A_LoopFileFullPath, "r")
    all := FileObj.Read()
    FileObj.Seek(0,0)
    Loop
        If (FileObj.ReadLine() = "---" && InStr(line := FileObj.ReadLine(), "Tag(s):") && FileObj.ReadLine() = "---") || A_Index = 100
            break
    If !InStr(line, "Tag(s):")
        continue
    line2 := StrReplace(line, "/", "")
    line2 := StrReplace(line2, " ", "/")
    line2 := StrReplace(line2, ".", "_")
    end := StrReplace(all,line, line2)
    FileObj.Close()
    FileDelete(A_LoopFileFullPath)
    FileAppend(end,A_LoopFileFullPath)
    all := line := line2 := end := ""
}
1 个赞

emeditor

搜索
(/(.)){1}
替换
\2

效果是这样的,感觉足够了
几个- - -被md效果遮盖了,变成了粗体
如果担心误伤,可用
搜索(/(.)){1}(/(.)){1}
替换\2\4
应该就可以的了
然后在emeditor菜单-搜索-多文件替换就可以了


Tag(s): I-文学 I7.1.2.0美国文学 I7.1.0北美文学 I7.1.2.1.0诗歌、韵文 I7-美洲文学 I7.1.2.1.020Walt-Whitman(1819-1892)/

好吧,发现根本不用那么复杂。

一次性直接把:
/(?<=\Tag([^/\n\r]+/)+)(?=[^\n\r]*\n)
替换成空,就去掉了/,其他类似。

这段代码匹配以“Tag开头的一行里的"/"字符”,可以免除对正文部分“/”的误伤。

1 个赞

这个脚本可以替换已经打开的文件
emeditor用的,代码保存为jsee
你一次性打开多少文件就看你电脑性能了
没有撤销,备份好文件

#title="macro"
#tooltip="macro",1033,"macro",1041,"macro",1029,"macro",1031,"macro",1036,"macro",3082,"macro",2058,"macro",1040,"macro",1042,"macro",1043,"macro",1049,"macro",2052,"macro",1028
#icon=""
#status=
Redraw = false;
DiscardUndo = true;
docs01 = new Enumerator( editor.Documents );
//打开的文件循环
for( ; !docs01.atEnd(); docs01.moveNext() )
{
doc01 = docs01.item();
doc01.Activate();
strName = doc01.Name;
var _regex="html"                              //这里html改成你要替换的文件后辍名
var regex=new RegExp(_regex,"gim");
var textInCurrentDocument=strName;
var matchResultArray=textInCurrentDocument.match(regex);
if (matchResultArray)
{
//以下是处理片段
document.selection.StartOfDocument(false);
nFlags=eeFindNext | eeFindSelectAll;
document.selection.Find("Tag(s)",nFlags);
document.selection.StartOfLine(true,eeLineLogical);
document.selection.EndOfLine(true,eeLineLogical);
nFlags=eeFindReplaceSelOnly | eeFindNext | eeReplaceAll;
document.selection.Replace(" ","",nFlags);
document.selection.Replace("/","",nFlags);
document.selection.Replace(".","_",nFlags);
document.selection.Collapse();
//以上是处理片段
document.close();
Redraw = false;
}
else
Redraw = true;
}

是emeditor吗?显示语法错误

在这个网站测试没有问题,可能各个软件对正则支持不太一样。。。。。。
总之语法是这么写的,什么软件支不支持就不晓得了

用专门的软件检查也没有问题

进一步研究发现,
能做到这种替换的属于deelx正则表达式引擎:
http://www.regexlab.com/zh/deelx

可以下载水淼·文件批量处理器,打开工具-正则调试器

上面选择单行,把 /(?<=Tag([^/\n\r]+/)+) 替换成空

然后点击批量替换,就可以把所有文件替换好了。

1 个赞

谢谢,已经试验过几次,不会误伤其他文本, 好用 :grinning:

想问一下,这个是不是只针对tag(s)这一行做出的处理?如果待处理的文本在标志开始的下一行,或者下几行,语句应该怎么写呢?

如果都在特定的下面几行,可以使用转跳语句
插入在下面这一句的下面
document.selection.Find(“Tag(s)”,nFlags);
具体的语句不太记得,我电脑不在旁边.
你可以去emeditor的在线帮助网页找找转跳语句.