使用 sed 将 xml 标记中的一个字符替换为另一个字符

使用 sed 将 xml 标记中的一个字符替换为另一个字符

我需要将字符替换ST

<episode-num system="onscreen">S1 E12</episode-num>

我期望的结果:

<episode-num system="onscreen">T1 E12</episode-num>

我不知道 Git 是如何深入工作的,我只是用它来替换我的 xml 标签中的那个字符,在论坛中研究我找到了一些信息并尝试了以下命令行:

sed -e :l -e 's@\(<episode-num system="onscreen">.*\)S\([^amp;]\)\(.*</episode-num>\)@\1T\2\3@;tl' guide.xml

但这不起作用,我希望你能帮助我。

答案1

假设您有一些 XML 文档,例如

<data>
<episode-num system="onscreen">S1 E12</episode-num>
<episode-num system="onscreen">S1 S12</episode-num>
<episode-num system="onscreen">T1 S12</episode-num>
</data>

...并且您想要替换节点值中S的所有字符Tepisode-num从...开始S

xmlstarlet你可以这样做:

xmlstarlet ed -u '//episode-num[starts-with(text(),"S")]' \
    -x 'translate(text(),"S","T")' file.xml

这可能会修改任何episode-num节点,无论它们位于文档中的哪个位置。如果你只想修改特别的节点,然后将//episode-numXPath 表达式更改为更精确的路径。

鉴于我上面的示例文档,xmlstarlet上面的命令将产生

<?xml version="1.0"?>
<data>
  <episode-num system="onscreen">T1 E12</episode-num>
  <episode-num system="onscreen">T1 T12</episode-num>
  <episode-num system="onscreen">T1 S12</episode-num>
</data>

xq(来自https://kislyuk.github.io/yq/) 与xmlstarlet上面一样:

xq -x '(.data."episode-num"[] | select (."#text"|startswith("S")))."#text" |= gsub("S";"T")' file.xml

这假设输入文档与我的示例文档具有相同的结构。它使用 XML 解析器解析文档,然后在内部将其转换为 JSON。它调用jq生成的 JSON 文档来应用给定的表达式,最后再次将所有内容转换回 XML。

对于我正在使用的示例文档,表达式实际应用到的内部 JSON 文档jq如下所示:

{
  "data": {
    "episode-num": [
      {
        "@system": "onscreen",
        "#text": "S1 E12"
      },
      {
        "@system": "onscreen",
        "#text": "S1 S12"
      },
      {
        "@system": "onscreen",
        "#text": "T1 S12"
      }
    ]
  }
}

答案2

仅当行包含另一个字符串时才替换某些字符串sed

我们仅替换包含字符串的行free

sed '/free/s/i/I/g' example.txt
  • '/free/s/i/I/g'
    • /free/- 仅当包含此字符串时才替换行
    • s- sed 的替代命令
    • /i/- 我们想要匹配什么正则表达式
    • /I/- 替换匹配的子字符串
    • /g- 替换标志,对线上的所有匹配项进行重复替换

您的假设的解决方案

你的测试字符串是<episode-num system="onscreen">

假设您有一个包含以下内容的文件:

$ cat test.xml 
<data>
<episode-num system="onscreen">S1 E11</episode-num>
<episode-num system="onscreen">S1 E12</episode-num>
<episode-num system="onscreen">T1 E13</episode-num>
<some data>S1 E1</episode-num>
</data>

您的 sed 解决方案是:

$ sed '/<episode-num system="onscreen">/s/S/T/g' test.xml 
<data>
<episode-num system="onscreen">T1 E11</episode-num>
<episode-num system="onscreen">T1 E12</episode-num>
<episode-num system="onscreen">T1 E13</episode-num>
<some data>S1 E1</episode-num>
</data>

该解决方案的来源是这里

答案3

Perl one-ligner 并不是一个好方法。反正:

perl -MXML::DT -e 'print dt("ex1.xml", "episode-num" => sub{$c=~ s/S/T/; toxml})'

在哪里:

  • -XML::DT = 导入并使用 XML::DT 模块(在本例中dt为函数
  • dt( file, processor)= 使用提供的处理器向下翻译文件
  • episode-num => sub{...}= 适用sub于每个元素episode-sum
  • $c = s/S/T/ ; toxml= 将元素内容中的 S 替换为 T (=$c) 并重新计算episodeXML 元素

(如有需要sudo cpanm XML::DT

相关内容