html - 仅在特定部分搜索和替换
问题描述
我有几千个 .html 文件,我需要搜索硬编码的服务器名称并将其替换为相对路径,但只能在页脚中。
例如
<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>
是否有任何工具可以进行这种搜索和替换?
解决方案
:- 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_codes),
anchor(Anchor_codes),
remainder(Rest_codes), !,
{
flatten([Footer_prefix_codes,Footer_start_tag_codes,Anchor_prefix_codes,Anchor_codes,Rest_codes],Codes),
string_codes(Html,Codes)
}.
anchor("<a href=\"http://changed/something\">") -->
"<a href=\"http://hardcoded/something\">".
是的,代码真的那么小!!!
这是通过将 HMTL 视为字符流而不是诸如DOM或XHTML之类的结构来实现的,这极大地简化了问题。这种技术不能在所有情况下都使用,但足以解决这个问题中提出的问题。
有关此技术限制的更多详细信息,请参阅此。
此版本anything//1
中使用的两个子句,rest_2//1
可以用库中的子句替换。
该库被添加到这里
:- use_module(library(dcg/basics)).
代码如何工作:
阅读所有内容<div class="footer">
string(Footer_prefix_codes),
{ Footer_start_tag_codes = "<div class=\"footer\">" },
Footer_start_tag_codes
注意:"<div class=\"footer\">"
绑定到一个变量,因为它需要两次,一次用于匹配输入,一次作为输出的一部分。通过将它放在一个变量中,它不必输入两次。
然后阅读所有内容<a href="http://hardcoded/something">
string(Anchor_prefix_codes)
并将其替换为<a href="http://changed/something">
anchor(Anchor_codes)
与
anchor("<a href=\"http://changed/something\">") -->
"<a href=\"http://hardcoded/something\">".
然后阅读剩下的所有内容。
remainder(Rest_codes)
一路上DCG将字符代码收集到列表中,
Footer_prefix_codes
Footer_start_tag_codes
Anchor_prefix_codes
Anchor_codes
Rest_codes
这些使用扁平化为一个列表
flatten([Footer_prefix_codes,Footer_start_tag_codes,Anchor_prefix_codes,Anchor_codes,Rest_codes],Codes)
并且字符代码列表Codes
被转换为一个字符串
string_codes(Html,Codes)
结果Html
。
这是测试用例
:- begin_tests(html_dcg).
test(004) :-
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_004(HTML_out),
phrase(DCG,HTML_in_codes,Rest),
format('~nHTML: ~n`~w''~n',[HTML_out]),
assertion( HTML_out == Expected_HTML_out ),
assertion( Rest == [] ).
:- end_tests(html_dcg).
测试用例运行示例:
?- run_tests(html_dcg:4).
% PL-Unit: html_dcg:4
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.
使用 DCG 真的就这么简单。在某些方面,DCG 类似于 BNF 和正则表达式;在乔姆斯基层次结构中,它们比正则表达式更强大。因此,如果正则表达式让您发疯,并且您不想使用解析器编写大量样板代码或使用解析器对抗解析冲突规则,请切换到 DCG。
享受。
Prolog 代码用于在目录中搜索类型为html
.
test_01 :-
Directory = 'C:\\Something',
process_directory(Directory,[],Items),
print_paths(Items).
process_directory(Directory,Items0,Items) :-
directory_files(Directory,Files),
process_files(Directory,Files,Items0,Items).
process_files(Directory,[File|Files],Items0,Items) :-
process_file(Directory,File,Items0,Items1),
process_files(Directory,Files,Items1,Items), !.
process_files(_Directory,[],Items,Items).
process_file(Directory,File,Items0,Items) :-
(
File = '.',
Items = Items0
;
File = '..',
Items = Items0
;
directory_file_path(Directory, File, Path),
exists_directory(Path),
process_directory(Path,Items0,Items1),
Items = Items1
;
directory_file_path(Directory, File, Path),
exists_file(Path),
(
file_name_extension(_Name, 'html', File),
Items = [Path|Items0]
;
Items = Items0
)
;
Items = Items0
).
print_paths([Path|Paths]) :-
format('~w~n',Path),
print_paths(Paths).
print_paths([]).
由于制作测试数据比较繁琐,这段代码我没有检查,所以在使用前检查一下。
如果您不确切知道自己在做什么,请在使用它之前备份您的目录。一个错误,它将清除所有文件,因为它在许多目录中写入了许多文件。
change_footer(Directory) :-
process_directory(Directory,[],Paths),
print_paths(Paths),
change_files(Paths).
change_files([Path|Paths]) :-
open(Path,write,Stream),
read_stream_to_codes(Stream,Codes),
DCG = dcg_change_004(HTML),
phrase(DCG,Codes),
format(Stream,HTML,[]),
close(Stream),
change_files(Paths).
change_files([]).
推荐阅读
- javascript - Microsoft Edge 中的语音识别 API(未定义)
- css - R Shiny中按索引号样式元素
- performance - 其中并发读/写操作的数据库策略
- debugging - 反汇编代码是崩溃同化的准确选择吗?
- ios - 我需要在 init(coder) 和 init(size) 中注入属性吗?
- php - 如何将 2 个按钮链接到同一页面上的 2 个单独的 php 代码?
- sharepoint-online - 如何使用 sp.web (SPFX) 获取文档库中文件的 URL
- c++ - 输出不是我所期望的
- laravel - 单击按钮后输入值不保持值
- rest - 成功登录的预期状态代码是什么