如何让sed跳过已完成匹配替换的内容?
Sed处理Markdown行内代码时的下划线转义问题
我需要用sed自动把文本转成Markdown格式:把符合[a-z0-9]+_[a-z0-9]+格式的内容用反引号包裹,同时只转义不在反引号内的下划线。
最初尝试的命令
echo "this is inline_code test 1_2 (_)" | sed -re "s/([a-z0-9]+_[a-z0-9]+)/\`\1\`/g;s/[_]/\\\\_/g"
执行结果:
this is `inline\_code` test `1\_2` (\_)
问题:反引号内部的下划线也被转义了,不符合Markdown行内代码的格式要求。
尝试用t分支命令改进
echo "this is inline_code test 1_2 (_)" | sed -re "s/([a-z0-9]+_[a-z0-9]+)/\`\1\`/g;t;s/[_]/\\\\_/g"
执行结果:
this is `inline_code` test `1_2` (_)
问题:t命令在第一个替换完成后直接跳到脚本末尾,导致外部括号里的下划线没被转义。
期望的正确结果
this is `inline_code` test `1_2` (\_)
解决方案
要实现“跳过已被反引号包裹的内容,只转义外部下划线”,可以用sed的循环扫描和分支命令来区分反引号内外的内容:
echo "this is inline_code test 1_2 (_)" | sed -re ' # 第一步:将目标内容用反引号包裹 s/([a-z0-9]+_[a-z0-9]+)/`\1`/g # 循环扫描,只转义不在反引号内的下划线 :scan # 匹配前面有偶数个反引号的下划线(即不在反引号内) s/^([^`]*(`[^`]*`)*[^`]*)_/\1\\_/ # 如果替换成功,回到scan标签继续处理 t scan '
执行这个命令就能得到符合预期的结果。
逻辑说明
- 先完成目标内容的反引号包裹,和之前的操作一致。
- 定义
scan循环标签,每次匹配不在反引号内的下划线(通过统计前面的反引号数量为偶数来判断),进行转义。 - 每次替换成功后回到
scan继续扫描,直到没有符合条件的下划线为止。
内容的提问来源于stack exchange,提问作者thomas
相关产品推荐
相关产品推荐

