仅在特定部分进行搜索和替换
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了仅在特定部分进行搜索和替换相关的知识,希望对你有一定的参考价值。
我有几千个.html文件,我需要搜索并将硬编码的服务器名称替换为相对路径,但仅限于页脚。
EG
<body>
<a href="http://hardcoded/something">This is ok</a>
... much more content here
<div class="footer">
<a href="http://hardcoded/something">Change this one</a>
</div>
</body>
有没有工具可以进行这种搜索和替换?
编辑
在发布这个答案后,我把它改进成了better answer。之所以留下这个答案是因为它有大部分的评论,并且是精致代码的垫脚石。
完整代码:
嫦娥.评论
:- set_prolog_flag(double_quotes, codes).
eos([], []).
dcg_change_002(Html) -->
{ Footer_start_tag = "<div class="footer">" },
anything(Footer_prefix),
Footer_start_tag, !,
anything(Anchor_prefix),
anchor_2(Anchor), !,
rest_2(Rest), !,
{
string_codes(Anchor_prefix,Anchor_prefix_codes),
string_codes(Anchor,Anchor_codes),
string_codes(Rest,Rest_codes),
append(Footer_prefix,Footer_start_tag,Part_1),
append(Part_1,Anchor_prefix_codes,Part_2),
append(Part_2,Anchor_codes,Part_3),
append(Part_3,Rest_codes,Html)
}.
anything([]) --> [].
anything([C|Cs]) -->
[C],
anything(Cs).
rest_2([]) --> call(eos).
rest_2([C|Cs]) -->
+ call(eos),
[C],
rest_2(Cs).
anchor_2("<a href="http://changed/something">") --> "<a href="http://hardcoded/something">".
测试用例:
:- begin_tests(html_dcg).
test(002) :-
HTML_in = "c
<body>
<a href="http://hardcoded/something">This is ok</a>
<div class="footer">
<a href="http://hardcoded/something">Change this one</a>
</div>
</body>",
Expected_HTML_out = "c
<body>
<a href="http://hardcoded/something">This is ok</a>
<div class="footer">
<a href="http://changed/something">Change this one</a>
</div>
</body>",
string_codes(HTML_in,HTML_in_codes),
DCG = dcg_change_002(HTML_out_codes),
phrase(DCG,HTML_in_codes,Rest),
string_codes(HTML_out,HTML_out_codes),
format('~nHTML: ~n`~w''~n',[HTML_out]),
assertion( HTML_out == Expected_HTML_out ),
assertion( Rest == [] ).
:- end_tests(html_dcg).
示例运行测试:
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.
For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).
?- consult("C:/change.pl").
true.
?- run_tests.
% PL-Unit: html_dcg
HTML:
`<body>
<a href="http://hardcoded/something">This is ok</a>
<div class="footer">
<a href="http://changed/something">Change this one</a>
</div>
</body>'
. done
% test passed
true.
通常,测试不会输出结果,例如format('~nHTML: ~n``~w''~n',[HTML_out])
但它被添加,所以你可以在测试中看到没有样板代码的结果。
由于这个更接近应该做的,这里是一个解释。
Prolog通常使用谓词编写,他们使用运算符:-
。 DCG是不同的,使用-->
。 DCG被翻译成常规Prolog,DCG可以通过使用{ ... }
包括常规Prolog。
DCG处理字符代码,在这种情况下因为这是所有ASCII文本,你可以使用ASCII table,但是尝试读取ASCII字符列表很难,所以,
:- set_prolog_flag(double_quotes, codes).
告诉编译器将" ... "
之间的任何内容转换为字符代码列表。
测试从测试用例开始
:- begin_tests(html_dcg).
:- end_tests(html_dcg).
设置一个名为htm_dcg
和的测试模块
test(002) :-
有一个名为002
的测试谓词。
HTML_in = "c
<body>
<a href="http://hardcoded/something">This is ok</a>
<div class="footer">
<a href="http://hardcoded/something">Change this one</a>
</div>
</body>"
这使用=/2(统一),它不是赋值,将HTML文本绑定到变量HTML_in
,但由于这是一个单独的模块,而不是代码,它是一个字符串,不会转换为字符代码列表。 c
是一个escape character,允许<body>
在下一行开始而不添加
到输入。 "
也必须作为"
逃脱为Prolog。
Expected_HTML_out = "c
<body>
<a href="http://hardcoded/something">This is ok</a>
<div class="footer">
<a href="http://changed/something">Change this one</a>
</div>
</body>"
同样为Expected_HTML_out
。
由于DCG需要代码,因此将字符串转换为代码
string_codes(HTML_in,HTML_in_codes)
实际上接下来的两行将被写成一行
phrase(dcg_change_002(HTML_out_codes),HTML_in_codes,Rest)
但这有点长而令人困惑。
phrase/3是从谓词到DCG的转换,以及为什么我在这个例子中明确地将接下来的两行写为
DCG = dcg_change_002(HTML_out_codes),
phrase(DCG,HTML_in_codes,Rest)
这样你就可以看到dcg_change_002/2
是一个DCG,它将返回HTML结果。它以codes
命名,表明它作为字符代码列表返回,而不是字符串。 Rest
过度杀戮但过去常常遇到一些罕见的错误
assertion( Rest == [] )
由于HTML作为字符代码列表返回,因此将其转换回字符串
string_codes(HTML_out,HTML_out_codes)
这样它就可以用了
format('~nHTML: ~n`~w''~n',[HTML_out])
打印HTML以证明有效的工作和
assertion( HTML_out == Expected_HTML_out )
表明代码返回预期的结果。
至于DCG,切入点是
dcg_change_002(Html) -->
并证明文本可以用作可匹配的模式
{ Footer_start_tag = "<div class="footer">" }
所以问题是要抓住所有文本到Footer_start_tag
并完成
anything(Footer_prefix)
然后匹配Footer_start_tag
Footer_start_tag, !,
!
将停止回溯,并且对于这次讨论来说太先进了,但是提高了性能,但它的使用在纯度圈中是不受欢迎的(长时间讨论,不要问)。
anything(Anchor_prefix)
现在我们在页脚中抓住所有文本到Anchor
。
anchor_2(Anchor), !,
这里Anchor
在
anchor_2("<a href="http://changed/something">") -->
"<a href="http://hardcoded/something">".
它与您要替换的代码匹配
"<a href="http://hardcoded/something">".
并返回要将其更改为的代码
"<a href="http://changed/something">"
你实际上可以制作一个这些规则的表格,如果你想要输入中的同一个位置,可以一次更改多个匹配项,例如这个锚点
最后抓住剩下的文字。
rest_2(Rest), !,
现在对于代码的一部分,我仍然不满意。
因为它全部在{ ... }
内,所以它不是DCG,而是在DCG中嵌入的常规Prolog。
{
string_codes(Anchor_prefix,Anchor_prefix_codes),
string_codes(Anchor,Anchor_codes),
string_codes(Rest,Rest_codes),
这是字符串到代码的更多转换。
append(Footer_prefix,Footer_start_tag,Part_1),
append(Part_1,Anchor_prefix_codes,Part_2),
append(Part_2,Anchor_codes,Part_3),
append(Part_3,Rest_codes,Html)
将所有字符列表重新附加到一个列表中,并将变量HTML
与结果绑定。
}.
}
只退出嵌入式代码。
anything([]) --> [].
anything([C|Cs]) -->
[C],
anything(Cs).
是一个标准的递归调用,只是抓取单个字符C
并使用|
将它们构建到一个列表中。
rest_2([]) --> call(eos).
rest_2([C|Cs]) -->
+ call(eos),
[C],
rest_2(Cs).
另一个标准的递归调用只是抓住单个字符C
并使用|
将它们构建成一个列表,但是这个正在寻找End Of Stream
因此eos
。 +
是Prolog的做法。
我知道很多人,如果不是大多数读过这个,这看起来很简单,但实际上它应该那么简单。您没有看到或听到更多程序员这样做的原因是学习逻辑编程,例如Prolog,很难,甚至那时Prolog上的很多课程都没有接近DCG。我花了好几年时间才达到这个水平,即便如此,按照大多数标准来说,这个代码并不是那么好,它可以完成工作,并且编写速度快,功能多样。
我希望发布另一个更高级和更简单的版本,但实际上这是我第一次尝试使用带有HTML的DCG。
:- use_module(library(dcg/basics)).
:- set_prolog_flag(double_quotes, codes).
dcg_change_004(Html) -->
string(Footer_prefix_codes),
{ Footer_start_tag_codes = "<div class="footer">" },
Footer_start_tag_codes,
string(Anchor_prefix_cod以上是关于仅在特定部分进行搜索和替换的主要内容,如果未能解决你的问题,请参考以下文章