在第一个匹配行之后替换第一个出现的行
Replacing first occurrence line after first matched line
让我们假设以下 XML 文件:
some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</addresses>
some other text
<addresses>
<something else/>
</addresses>
...
我需要将第一个 <addresses xmlns="namespace">
之后的第一个 </addresses>
替换为 </namespace:addresses>
,以便文件变为:
some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</namespace:addresses>
some other text
<addresses>
<something else/>
</addresses>
...
我知道 ,但是 none 以下解决方案改变了一切:
sed -e '/<addresses xmlns="namespace">/!b' -e ':a' -e "s/<\/namespace:addresses>/<\/addresses>/;t trail" -e 'n;ba' -e ':trail' -e 'n;btrail' file.xml
sed -e "/<addresses xmlns=\"namespace\">/,/./ s/<\/namespace:addresses>/<\/addresses>/" file.xml
sed -e "/<addresses xmlns=\"namespace\">/,/<\/namespace:addresses>/ s/<\/namespace:addresses>/<\/addresses>/" file.xml
例如:
sed -e "/<addresses xmlns=\"namespace\">/,/./ s/<\/namespace:addresses>/<\/addresses>/" file.xml
some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</addresses>
some other text
<addresses>
<something else/>
</addresses>
...
也许这个问题与我正在使用的 sed 有关:impish/21.10 上的 4.7-1ubuntu1 甚至 4.8-1.
有什么建议吗?
我对任何其他工具都持开放态度 (perl/awk),越简单越好。
perl
比 sed
容易得多:
perl -0777 -i -pe 's~<(addresses)\s+xmlns="namespace">[^<]*(?:<(?!/>)[^<]*)*\K</>~</namespace:>~' file
参见 online demo。 详情:
<(addresses)\s+xmlns="namespace">[^<]*(?:<(?!/>)[^<]*)*\K</>
- 正则表达式模式匹配
<
- 一个 <
字符
(addresses)
- 第 1 组 (</code>):<code>addresses
\s+
- 一个或多个空格
xmlns="namespace">
- 固定字符串
[^<]*(?:<(?!/>)[^<]*)*
- 比 (?s:.)*?
更快的替代方案 - 基本上,匹配任何文本直到 </addresses>
字符串
\K
- 匹配重置运算符,它会忽略当前匹配内存缓冲区中到目前为止匹配的所有文本
</>
——(这个是最后消耗掉的,会被替换掉的):</
+ 第1组值(以免重复addresses
)+ >
</namespace:>
- 替换为 </namespace:
+ 第 1 组值 + >
.
它取代了第一次出现,因为 -0777
将文件压缩成一个多行文本并且没有 g
标志。
请注意模式内的 </code> 反向引用语法与 <code>perl
命令中替换模式中的 </code> 替换反向引用之间的区别。</p>
<p>参见<a href="https://ideone.com/RNRzWK" rel="nofollow noreferrer">online demo</a>:</p>
<pre><code>s=' some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</addresses>
some other text
<addresses>
<something else/>
</addresses>
...'
perl -0777 -pe 's~<(addresses)\s+xmlns="namespace">[^<]*(?:<(?!/>)[^<]*)*\K</>~</namespace:>~' <<< "$s"
输出:
some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</namespace:addresses>
some other text
<addresses>
<something else/>
</addresses>
...
让我们假设以下 XML 文件:
some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</addresses>
some other text
<addresses>
<something else/>
</addresses>
...
我需要将第一个 <addresses xmlns="namespace">
之后的第一个 </addresses>
替换为 </namespace:addresses>
,以便文件变为:
some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</namespace:addresses>
some other text
<addresses>
<something else/>
</addresses>
...
我知道
sed -e '/<addresses xmlns="namespace">/!b' -e ':a' -e "s/<\/namespace:addresses>/<\/addresses>/;t trail" -e 'n;ba' -e ':trail' -e 'n;btrail' file.xml
sed -e "/<addresses xmlns=\"namespace\">/,/./ s/<\/namespace:addresses>/<\/addresses>/" file.xml
sed -e "/<addresses xmlns=\"namespace\">/,/<\/namespace:addresses>/ s/<\/namespace:addresses>/<\/addresses>/" file.xml
例如:
sed -e "/<addresses xmlns=\"namespace\">/,/./ s/<\/namespace:addresses>/<\/addresses>/" file.xml
some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</addresses>
some other text
<addresses>
<something else/>
</addresses>
...
也许这个问题与我正在使用的 sed 有关:impish/21.10 上的 4.7-1ubuntu1 甚至 4.8-1.
有什么建议吗? 我对任何其他工具都持开放态度 (perl/awk),越简单越好。
perl
比 sed
容易得多:
perl -0777 -i -pe 's~<(addresses)\s+xmlns="namespace">[^<]*(?:<(?!/>)[^<]*)*\K</>~</namespace:>~' file
参见 online demo。 详情:
<(addresses)\s+xmlns="namespace">[^<]*(?:<(?!/>)[^<]*)*\K</>
- 正则表达式模式匹配<
- 一个<
字符(addresses)
- 第 1 组 (</code>):<code>addresses
\s+
- 一个或多个空格xmlns="namespace">
- 固定字符串[^<]*(?:<(?!/>)[^<]*)*
- 比(?s:.)*?
更快的替代方案 - 基本上,匹配任何文本直到</addresses>
字符串\K
- 匹配重置运算符,它会忽略当前匹配内存缓冲区中到目前为止匹配的所有文本</>
——(这个是最后消耗掉的,会被替换掉的):</
+ 第1组值(以免重复addresses
)+>
</namespace:>
- 替换为</namespace:
+ 第 1 组值 +>
.
它取代了第一次出现,因为 -0777
将文件压缩成一个多行文本并且没有 g
标志。
请注意模式内的 </code> 反向引用语法与 <code>perl
命令中替换模式中的 </code> 替换反向引用之间的区别。</p>
<p>参见<a href="https://ideone.com/RNRzWK" rel="nofollow noreferrer">online demo</a>:</p>
<pre><code>s=' some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</addresses>
some other text
<addresses>
<something else/>
</addresses>
...'
perl -0777 -pe 's~<(addresses)\s+xmlns="namespace">[^<]*(?:<(?!/>)[^<]*)*\K</>~</namespace:>~' <<< "$s"
输出:
some text
<addresses>
<something/>
</addresses>
some more text
<addresses xmlns="namespace">
<could be anything/>
</namespace:addresses>
some other text
<addresses>
<something else/>
</addresses>
...