仅当给定文本在其前面时才用文本替换字符串
Replace string with text only when a given text precedes it
我有大约一百个 Markdown 文件,其中包含这样的 Latex 片段:
<div latex="true" class="task" id="Task">
(@) Delete the fourth patterns from your .teach file and your .data files. Remember to change the second line in each so that Tlearn knows there are now only three patterns.
- They should look like [@fig:dataTeach]
</div>
我想用更易于阅读的伪标签替换 <div>
标签,如下所示:
<task>
(@) Delete the fourth patterns from your .teach file and your .data files. Remember to change the second line in each so that Tlearn knows there are now only three patterns.
- They should look like [@fig:dataTeach]
</task>
如果我所有的 <div>
标签都标记 'tasks',这将是微不足道的,但我有类似的 div 'journal' 和 'highlight'。我需要一个过程,仅当前面的 <div>
具有 class 或 id 'task' 时,才会将 </div>
更改为 </task>
,同样对于 'journal' 和 'highlight'。
查看 Stack Overflow 一段时间后,我发现许多多行搜索和替换的示例几乎可以完成我想做的事情,但是语法(尤其是 sed)很难理清,我无法适应它用于上述情况。我的下一个选择是编写一个 bash 脚本来逐行循环,但我觉得这可能太脆弱了。
干杯
伊恩
这应该可以解决问题:
$msys\bin\sed -En "s/<div latex=\"true\" class=\"task\" id=\"Task\">/<task>/;T;{:a;N;s/<\/div>/<\/task>/;Ta;p;}" input.txt
这些是构建基块,以备不时之需:
- 做一个循环:
{:a;
- 第二次替换触发时结束:
s/<\/div>/<\/task>/;Ta;
- 只启动它,如果第一个替换被触发:
s/<div latex=\"true\" class=\"task\" id=\"Task\">/<task>/;T;
- 在循环内只是将行收集到模式 space:
N;
- 在循环结束时打印:
p;}
- 使用扩展的正则表达式调用并且没有默认打印
(我的是 windows/msys sed,你知道的):$msys\bin\sed -En
不需要循环。只需通过管道传输文件...
sed '/Task/s/<div.*>/<task>/g;s/<\/div>/<\/task>/g'
开头的 /Task
使 sed
只编辑名称为 Task
的行。
使用 s/NAME/NEWNAME/
可以一个接一个地替换一些文本。
添加 .*
将替换从此时开始的所有文本。
最后但同样重要的是,g
代表全局,将以这种方式编辑所有条目。
第二个命令(在 ;
之后)将用 </task>
替换 </div>
。它和以前一样是同一命令的一部分。这次的不同之处在于 /
(斜杠)将由 sed
自己使用,如果没有以其他方式声明的话!这可以通过 \
(反斜杠)进行存档。
给你。您的文件的输出将如下所示....
<task>
(@) Delete the fourth patterns from your .teach file and your .data files. Remember to change the second line in each so that Tlearn knows there are now only three patterns.
- They should look like [@fig:dataTeach]
</task>
以下 awk
命令在以下假设下一般有效:
所有开始和结束 div
标签都在各自的行上。
属性全部使用"
-quoting.
新的标签名称仅来自 class
属性的值(如果规则更清晰,这可以推广)。
awk -F ' class="' '
/^<div / && NF > 1 { tag=; sub("\".*", "", tag); printf "<%s>\n", tag; next }
/^<\/div>/ && tag != "" { printf "</%s>\n", tag; tag=""; next }
1
' file
-F ' class="'
有效地将每一行拆分为 class
属性之前(字段 1,</code>)和之后(字段 2,<code>
) ,如果存在。因此,只有具有此类属性的行才会有超过 1 个字段 (NF > 1
).
正在处理开头 div
标签:
Pattern /^<div / && NF > 1
因此仅匹配以 (^
) <div
和 (&&
) 开头且包含 class
的行属性 (NF > 1
)
tag=; sub("\".*", "", tag)
从第二个字段中提取 class
属性值,通过替换第一个 "
中的所有内容(结束 "
属性值)与空字符串,有效地只在变量 tag
.
中保留属性值
printf "<%s>\n", tag
打印属性值作为替换开始标记。
next
跳过脚本的其余部分并移至下一个输入行。
正在处理结束 div
标记:
/^<\/div>/ && tag != ""
与结束 div
标签相匹配,假设在前一个开始标签 (tag != ""
) 中找到了 class
属性值。
printf "</%s>\n", tag
打印新的结束标记。
tag=""
重置最近的替换标签,这样任何后续 div
没有 class
属性的元素也不会意外重命名。
next
跳过脚本的其余部分并移至下一个输入行。
所有其他行:
1
只是按原样打印所有其他行。 (1
是 { print }
的常见 Awk shorthand:模式 1
,解释为布尔值,根据定义为真,并且没有关联操作的模式 { ... }
默认打印输入行)。
这可能适合您 (GNU sed):
v='task|journal|highlight'
sed -ri '/^<div/{:a;N;/^<\/div/M!ba;s/^<.*class="('$v')"[^>]*(.*<\/)div/</}' file1 file2 file3 ...
这会将 div
语句存储在模式 space 中,然后根据预先设置的 shell 变量替换(或不替换)所需的值。
N.B。备选方案存储在 shell 变量 v
中,由 |
分隔
我有大约一百个 Markdown 文件,其中包含这样的 Latex 片段:
<div latex="true" class="task" id="Task">
(@) Delete the fourth patterns from your .teach file and your .data files. Remember to change the second line in each so that Tlearn knows there are now only three patterns.
- They should look like [@fig:dataTeach]
</div>
我想用更易于阅读的伪标签替换 <div>
标签,如下所示:
<task>
(@) Delete the fourth patterns from your .teach file and your .data files. Remember to change the second line in each so that Tlearn knows there are now only three patterns.
- They should look like [@fig:dataTeach]
</task>
如果我所有的 <div>
标签都标记 'tasks',这将是微不足道的,但我有类似的 div 'journal' 和 'highlight'。我需要一个过程,仅当前面的 <div>
具有 class 或 id 'task' 时,才会将 </div>
更改为 </task>
,同样对于 'journal' 和 'highlight'。
查看 Stack Overflow 一段时间后,我发现许多多行搜索和替换的示例几乎可以完成我想做的事情,但是语法(尤其是 sed)很难理清,我无法适应它用于上述情况。我的下一个选择是编写一个 bash 脚本来逐行循环,但我觉得这可能太脆弱了。
干杯
伊恩
这应该可以解决问题:
$msys\bin\sed -En "s/<div latex=\"true\" class=\"task\" id=\"Task\">/<task>/;T;{:a;N;s/<\/div>/<\/task>/;Ta;p;}" input.txt
这些是构建基块,以备不时之需:
- 做一个循环:
{:a;
- 第二次替换触发时结束:
s/<\/div>/<\/task>/;Ta;
- 只启动它,如果第一个替换被触发:
s/<div latex=\"true\" class=\"task\" id=\"Task\">/<task>/;T;
- 在循环内只是将行收集到模式 space:
N;
- 在循环结束时打印:
p;}
- 使用扩展的正则表达式调用并且没有默认打印
(我的是 windows/msys sed,你知道的):$msys\bin\sed -En
不需要循环。只需通过管道传输文件...
sed '/Task/s/<div.*>/<task>/g;s/<\/div>/<\/task>/g'
开头的 /Task
使 sed
只编辑名称为 Task
的行。
使用 s/NAME/NEWNAME/
可以一个接一个地替换一些文本。
添加 .*
将替换从此时开始的所有文本。
最后但同样重要的是,g
代表全局,将以这种方式编辑所有条目。
第二个命令(在 ;
之后)将用 </task>
替换 </div>
。它和以前一样是同一命令的一部分。这次的不同之处在于 /
(斜杠)将由 sed
自己使用,如果没有以其他方式声明的话!这可以通过 \
(反斜杠)进行存档。
给你。您的文件的输出将如下所示....
<task>
(@) Delete the fourth patterns from your .teach file and your .data files. Remember to change the second line in each so that Tlearn knows there are now only three patterns.
- They should look like [@fig:dataTeach]
</task>
以下 awk
命令在以下假设下一般有效:
所有开始和结束
div
标签都在各自的行上。属性全部使用
"
-quoting.新的标签名称仅来自
class
属性的值(如果规则更清晰,这可以推广)。
awk -F ' class="' '
/^<div / && NF > 1 { tag=; sub("\".*", "", tag); printf "<%s>\n", tag; next }
/^<\/div>/ && tag != "" { printf "</%s>\n", tag; tag=""; next }
1
' file
-F ' class="'
有效地将每一行拆分为class
属性之前(字段 1,</code>)和之后(字段 2,<code>
) ,如果存在。因此,只有具有此类属性的行才会有超过 1 个字段 (NF > 1
).正在处理开头
div
标签:Pattern
/^<div / && NF > 1
因此仅匹配以 (^
)<div
和 (&&
) 开头且包含class
的行属性 (NF > 1
)tag=; sub("\".*", "", tag)
从第二个字段中提取class
属性值,通过替换第一个"
中的所有内容(结束"
属性值)与空字符串,有效地只在变量tag
. 中保留属性值
printf "<%s>\n", tag
打印属性值作为替换开始标记。next
跳过脚本的其余部分并移至下一个输入行。
正在处理结束
div
标记:/^<\/div>/ && tag != ""
与结束div
标签相匹配,假设在前一个开始标签 (tag != ""
) 中找到了class
属性值。printf "</%s>\n", tag
打印新的结束标记。tag=""
重置最近的替换标签,这样任何后续div
没有class
属性的元素也不会意外重命名。next
跳过脚本的其余部分并移至下一个输入行。
所有其他行:
1
只是按原样打印所有其他行。 (1
是{ print }
的常见 Awk shorthand:模式1
,解释为布尔值,根据定义为真,并且没有关联操作的模式{ ... }
默认打印输入行)。
这可能适合您 (GNU sed):
v='task|journal|highlight'
sed -ri '/^<div/{:a;N;/^<\/div/M!ba;s/^<.*class="('$v')"[^>]*(.*<\/)div/</}' file1 file2 file3 ...
这会将 div
语句存储在模式 space 中,然后根据预先设置的 shell 变量替换(或不替换)所需的值。
N.B。备选方案存储在 shell 变量 v
中,由 |