4

我的问题与shell 脚本类似:搜索和替换多行,但有一个小例外。

在链接的问题中,用户想要这样做:

source:
[stuff before]
<!--WIERD_SPECIAL_COMMENT_BEGIN-->
  [stuff here, possibly multiple lines.
<!--WIERD_SPECIAL_COMMENT_END-->
[stuff after]    

target:
[stuff before]
[new content]
[stuff after]

我的问题类似,我想这样做:

source:
[stuff before]
<!--WIERD_SPECIAL_COMMENT_BEGIN-->
  [this]
<!--WIERD_SPECIAL_COMMENT_END-->
<!--WIERD_SPECIAL_COMMENT_BEGIN-->
  [not this]
<!--WIERD_SPECIAL_COMMENT_END-->
[stuff after]    

target:
[stuff before]
[new content]
<!--WIERD_SPECIAL_COMMENT_BEGIN-->
  [not this]
<!--WIERD_SPECIAL_COMMENT_END-->
[stuff after]

在适当的多行正则表达式中,这很容易做到:

/<!--WIERD_SPECIAL_COMMENT_BEGIN-->.*[this].*<!--WIERD_SPECIAL_COMMENT_END-->/m

但是链接问题中建议的答案使用正则表达式作为不允许检查两个外围边界之间的线的范围。

有没有办法将一个范围内的所有行添加到模式缓冲区,以便我可以一次对所有行进行正则表达式?例如:

sed '
    #range between comment beginning and comment end
    /<!--WIERD_SPECIAL_COMMENT_BEGIN-->/,/<!--WIERD_SPECIAL_COMMENT_END-->/
    #Do something to add the lines in this range to pattern buffer
    /.*[this].*/d
    #Delete all the lines if [this] is in the pattern buffer
' <in.txt >out.txt
4

5 回答 5

3

使用 Perl,它相对简单。

perl -0777pe 's/<!--BEGIN-->\n(?:(?!<!--END-->\n).)*?\[this\].*?\n<!--END-->\n/[new content]\n/s' in.txt

Perl 提供的好处是(a)-0777“slurp 模式”,它一次性拉入整个输入文件,而不是一次sed一行的处理;(b)/s允许点匹配换行符的正则表达式标志;(c) 吝啬的重复运算符*?和朋友,这导致重复匹配尽可能少而不是尽可能多;最后是 (d) 否定前瞻(?!...),它允许您在否定前瞻表达式匹配的地方禁止匹配。(没有这个,如果“stuff before”文本中有一个“假”的起始分隔符,即使是吝啬的匹配也会匹配结束分隔符。)......当然,(e)一种通用编程语言,其中sed只有适用于相对简单的文本处理任务。

(我使用了更简单的开始和结束分隔符。我希望“奇怪”是故意拼写错误。)

于 2012-07-29T16:29:49.497 回答
0

免责声明:我是初学者。这肯定不是最好的方法。


我分三步做了类似的事情。假设您在 Linux 上运行,您可以执行以下操作:

1)用特殊字符替换文件中所有出现的换行符:

cat originalText.txt | tr '\n' '~' > temp

2)使用您最喜欢的方法(我使用perl)执行您的正则表达式,在您期望换行符的每个位置放置一个特殊字符的实例。确保保持特殊换行符不变。

3)这次以相反的方式执行第一个命令:

cat temp | tr '~' '\n' > modText.txt

我希望这有帮助。

于 2012-07-27T15:56:26.313 回答
0

有没有办法将一个范围内的所有行添加到模式缓冲区,以便我可以一次对所有行进行正则表达式?

当然,使用保持空间。例如:

sed -n '/begin/,/end/{ /begin/{h;d};H}; /end/{g;s/\n/<newline>/gp}'

将用文本替换匹配“开始”和“结束”的行之间的换行符<newline>

于 2012-07-27T16:35:06.557 回答
0

这可能对您有用(GNU sed):

sed ':a;$!N;/^<!--WIERD_SPECIAL_COMMENT_BEGIN-->/!{P;D};/<!--WIERD_SPECIAL_COMMENT_END-->$/!ba;s/\[this\]/[new content]/;p;d' file
于 2012-07-28T06:31:44.780 回答
-1

你可以这样做sed

解析.sed

/BEGIN/ {               # If we encounter BEGIN
  :a                    # Read all until END
  N                     # into pattern space
  /END/!ba              # /
  /\[this\]/d           # If the block contains [this], delete it
  s/^/[new content]\n/  # Insert [new content] before the block
}

像这样运行它:

sed -f parse.sed infile

输出:

[stuff before]
[new content]
<!--WIERD_SPECIAL_COMMENT_BEGIN-->
  [not this]
<!--WIERD_SPECIAL_COMMENT_END-->
[stuff after]
于 2012-07-27T15:47:07.043 回答