替换字符串,但仅当它是该字符串在特定行之前的最后一次出现时

  • 本文关键字:字符串 最后一次 替换 sed
  • 更新时间 :
  • 英文 :


我正在将自定义标记语言转换为TeX.

我有一个这样的文件:

macro{stuff}
{more stuff}
{yet other stuff}
{some stuff}
these are extra lines
another extra line
there can be any number of extra lines
e
macro{yet more stuff stuff}
{even more stuff}
{yet other stuff}
{some stuff}
this is extra
this is extra too
e

我需要这样的结果:

macro{stuff}
{more stuff}
{yet other stuff}
{some stuff}{
these are extra lines
another extra line
there can be any number of extra lines
}
macro{yet more stuff stuff}
{even more stuff}
{yet other stuff}
{some stuff}{
this is extra
this is extra too
}

请注意,e本身就在一行上,表示一组数据的末尾,它只是被一个右括号取代。

我可以简单地使用这个:

sed -i 's/^e$/}/g' file.tex

结果是:

macro{stuff}
{more stuff}
{yet other stuff}
{some stuff}
these are extra lines
another extra line
there can be any number of extra lines
}
macro{yet more stuff stuff}
{even more stuff}
{yet other stuff}
{some stuff}
this is extra
this is extra too
}

问题是,我还需要一个匹配的起始括号来包围e之前的额外文本。

一种方法是:

  1. 替换每次出现的}
  2. 但前提是这种情况已经结束
  3. 并且仅当它是在e完全自己出现之前出现的最后一个事件

这是我能想到的最接近的数字,不确定如何在不包含更多}$:匹配的任何行之间进行匹配

sed -i 's/}$n.*n.*n.*n^e$/}{&}/g' file.tex

如何将最后的额外文本包装在{}中?

使用空RS使用awk更容易做到这一点。以下是gnu-awk解决方案:

awk -v RS= '{sub(/.*}/, "&{"); sub(/ne$/, "n}"); ORS=RT} 1' file
macro{stuff}
{more stuff}
{yet other stuff}
{some stuff}{
these are extra lines
another extra line
there can be any number of extra lines
}
macro{yet more stuff stuff}
{even more stuff}
{yet other stuff}
{some stuff}{
this is extra
this is extra too
}

或者在任何版本的awk:中

awk -v RS= '{sub(/.*}/, "&{"); sub(/ne$/, "n}n")} 1' file

没有@anubhava的awk解决方案那么简洁或优雅,但作为练习,我在GNUsed中实现了相同的解决方案。

sed -n '/^e$/{ z; x; s/.*}/&{/; s/$/n}/; p; d; }; /^$/d; H; ${ H; x; p; }' file

分解-
/^e$/{ z; x; s/.*}/&{/; s/$/n}/; p; d; };通过组件
/^e$/{ ... }在只有e的行上执行此操作列表:
z是一个清空模式空间的GNU选项
xex更改模式和保留空格
s/.*}/&{/在块中最后一个闭合的paren之后添加一个打开的paren
s/$/n}/e所在的位置添加新行和}
pp打印图案空间,dd删除记录并继续。

/^$/d删除之间的空记录
H表示H将模式空间记录旧(追加(到保持空间上,以便我们累积块,直到到达下一个e终止符行或结束。

${ H; x; p; }只是确保打印最后一个e之后的任何记录
如果你不在乎,或者你知道不应该有,就跳过它。

如果你不使用GNUsed,它看起来会有点不同,哈哈

使用所提供的输入,匹配}之间的任何内容,直到线路上的e-带有-z选项的GNU sed:

sed -Ez 's/([^}]*)ne(n|$)/{1n}2/g'

这是我喜欢使用tac的地方

tac file | awk '
/^e$/ {print "}"; p=1; next}
p && /^{/ {print $0 "{"; p=0; next}
1
' | tac

该awk命令在第一行添加大括号,从替换e后的大括号开始。

当我看到诸如";为最后X〃做一些事情;,我认为"反转文件并首先对X执行操作,然后重新反转文件

如果ed可用/可接受。

脚本script.ed

g?^e$?s/.*/}/
?^{.*?s/$/{/
,p
Q

ed -s file.txt < script.ed

在一行中,引用bash$''的语法

printf '%sn' $'g?^e$?s/.*/}/\n?^{.*?s/$/{/' ,p Q | ed -s file.txt

这可能对你有用(GNU sed(:

sed 'N;s/}n([^{])/}{n1/;s/ne$/n}/;P;D' file

有两种情况需要替换:

  1. 当一行以}结束,但下一行不以{开始时
  2. 当一行仅包含CCD_ 45

通过使用NPD命令打开两行窗口,可以满足这两种条件。

第一种方法是将{附加到窗口的第一行。

第二种方法是将CCD_ 50替换为CCD_。

相关内容

最新更新