我有一个充满 html 文件的目录,这些文件都有我想要删除的某些标签。例如,在<p class="message"> </p>
我想要消失的所有文件中,但每个文件中标签内的文本都不同。
对于每个文件中的文本相同的情况,我一直在使用
find . -type f -name '*.html' -exec sed -i'' -e 's/existing/replacement/g' {} +
用新文本替换旧文本。然而,在上面的示例中,标签之间的不同文本意味着这不起作用。
是否有类似的命令或工具可以让我删除或替换两个指定字符串之间的所有内容?
答案1
HTML 标签通常可以跨越多行,或者每行可能有多个标签,因此您可以使用perl
的 slurp 模式,其中文件的完整内容作为一个整体进行处理,并且其*?
非贪婪版本可以*
匹配尽可能少的内容可以在开始标签和结束标签之间。
这些-i
选项也是非标准的,那些支持它的选项实际上是perl
从不使用备份后缀(-i
vs -i ''
)时进行变体复制而来的。
find . -name '*.html' -type f -exec perl -0777 -pi -e '
s{<p class="message">.*?</p>}{ }gs' {} +
答案2
使用乐(以前称为 Perl_6)
~$ raku -e 'my regex L { "<p class=\"message\">" }; \
my regex R { "</p>" }; \ \
my $dest-dir = "/path/to/destination/dir/"; \
for dir() -> $file { \
with $file.slurp { / <L> .*? <R> / \
?? my $new-file = .subst( :g, / <L> <(.*?)> <R> / ) \
!! next; \
spurt("$dest-dir" ~ "$file".IO, $new-file) \
} \
};'
Raku 是 Perl 编程语言家族中的一种编程语言。简而言之,L
-和-正则R
表达式都被声明并分配了一个值。$dest-dir
声明一个标量并为其分配一个字符串。当前dir()
通过 进行迭代for
,并且$file
在以下块中分析/修改每个 .IO 对象。
在外部块中,$file
ed slurp
(一次读取全部),在内部块中,立即测试该文本是否存在正则表达式,其中包含.*?
“任何字符零次或多次,节俭地采取”正则表达式介于两者之间。注意这里的L
-and-R
正则表达式必须用尖括号插入,即<L>
-and- <R>
,因为它们在/ ... /
匹配器内),
内部块 Raku 的三元运算符 测试 ??
真的 !!
错误的 用来。如果找到串联的 3 个正则表达式,则中心“原子”现在被...捕获标记<(.*?)>
包裹,表明外部匹配将被删除,并且仅被删除(没有任何内容)。 A是通过删除这些内部字符而创建的。如果未找到正则表达式,则块向前跳至文件(退出内部块)。这允许新创建的文件以原始名称写出 ( ed) 到正确的目录。<(
)>
.*?
subst
$new-file
next
$new-file
spurt
$file
输入示例(原始dir/file
):
first line
<p class="message"> foo </p>
<p class="message"> bar </p>
<p class="message">
baz
</p>
last line
示例输出(写入 new dir/file
)
first line
<p class="message"></p>
<p class="message"></p>
<p class="message"></p>
last line
上面的“示例输出”显示了指定 html 标记的内部文本被删除的三个实例,即使开始/结束标记位于不同的行上。为了用新的(文字字符串)文本替换,请更改以下代码段。
从:
.subst( :g, / <L> <(.*?)> <R> / )
到:
.subst( :g, / <L> <(.*?)> <R> /, "new-text" )
https://docs.raku.org/routine/dir
https://docs.raku.org/type/Regex
https://raku.org
答案3
就我个人而言,我讨厌得到“看看这个”作为答案。然而,在这种情况下,另一个线程很好地解释了这个确切的过程。