是否有正则表达式、perl 或 sed 可以从文件中的一组特定行中删除一行?
Is there a regex, perl, or sed that can remove one line from a particular group of lines in a file?
例如,如果我有类似的东西:
<Mansions \>
windows
walls
floors
<\Mansions>
我想移除墙并保留其他行我该如何使用正则表达式或者是否有比正则表达式更好的选择?
所以我需要它看起来像:
<Mansions \>
windows
floors
<\Mansions>
并且在我移除墙壁后上面的线条仍然存在。所以我们的目标是搜索文件中的那组行并删除一个词并仍然保留其他词在那里和组中。
请记住,我只是更改文件中的这个组,而不是文件中单词的一个实例,因为那样会是一个更简单的表达式。
我试过使用正则表达式:
^(<Mansion\s*"/.*/.*">)((?:\n(?!.*(?:walls\s(floor|windows)+.*\n|</Mansion>)).*)*\n</Mansion>)$
但是当我删除像 walls 这样的单个词时,这不起作用
那么是否可以使用正则表达式来处理这样的事情?
在 Perl 中,您可以尝试以下操作:
use feature qw(say);
use strict;
use warnings;
my $str = '
<Mansions \>
walls
windows
floors
<\Mansions>';
my $word = 'walls';
$str =~ s/^(\s*<Mansions\s*\>)(.*?)(<\Mansions>)/do_replace(, , , $word)/mseg;
say $str;
sub do_replace {
my ( $header, $group, $closer, $word ) = @_;
$header. ($group =~ s/\n?^\s*\Q$word\E\s*$//mr) . $closer;
}
输出:
<Mansions \>
windows
floors
<\Mansions>
这是一个 Perl 单行代码,它使用触发器运算符 (..
) 仅对两个正则表达式匹配项中的文本进行操作。如果它匹配 /wall/
并且在开始和结束文本内,它会跳过该行。
perl -ne '/walls/ && next if /Mansions \/ .. /<\Mansions>/; print' file.txt
如果这些组没有在彼此内部分组,sed 脚本可能会起作用:
script.sed
/<Mansions \>/,/<\Mansions>/ {
/^[[:blank:]]*walls[[:blank:]]*$/ d
}
你运行它喜欢sed -Ef script.sed yourfile
。
说明
/<Mansions \>/,/<\Mansions>/ { ... }
注意内部表达式仅应用于 <Mansions \>
和 <\Mansions>
之间的行。当 Mansions 被分组在其他 Mansions 中时,这将不起作用。
/^[[:blank:]]*walls[[:blank:]]*$/ ...
选择由单词 walls
和可选的前导和尾随空格组成的行。
d
表示删除这些行。
$ awk '/<\Mansions>/{f=0} f && /walls/{next} /<Mansions \>/{f=1} 1' file
<Mansions \>
windows
floors
<\Mansions>
以上内容在任何 UNIX 机器上使用任何 shell 中的任何 awk 都可以工作。
你为什么这么难?如前所述,您的问题不需要代码或正则表达式或纯香草查找和替换功能以外的任何东西。如果您的问题中隐藏了其他需要代码答案的内容,我找不到。
- 打开查找和替换。
在 Find
中使用:
<Mansions \>
windows
walls
floors
<\Mansions>
在 Replace
中使用:
<Mansions \>
windows
floors
<\Mansions>
单击Replace All
。
任务完成。
例如,如果我有类似的东西:
<Mansions \>
windows
walls
floors
<\Mansions>
我想移除墙并保留其他行我该如何使用正则表达式或者是否有比正则表达式更好的选择?
所以我需要它看起来像:
<Mansions \>
windows
floors
<\Mansions>
并且在我移除墙壁后上面的线条仍然存在。所以我们的目标是搜索文件中的那组行并删除一个词并仍然保留其他词在那里和组中。
请记住,我只是更改文件中的这个组,而不是文件中单词的一个实例,因为那样会是一个更简单的表达式。
我试过使用正则表达式:
^(<Mansion\s*"/.*/.*">)((?:\n(?!.*(?:walls\s(floor|windows)+.*\n|</Mansion>)).*)*\n</Mansion>)$
但是当我删除像 walls 这样的单个词时,这不起作用
那么是否可以使用正则表达式来处理这样的事情?
在 Perl 中,您可以尝试以下操作:
use feature qw(say);
use strict;
use warnings;
my $str = '
<Mansions \>
walls
windows
floors
<\Mansions>';
my $word = 'walls';
$str =~ s/^(\s*<Mansions\s*\>)(.*?)(<\Mansions>)/do_replace(, , , $word)/mseg;
say $str;
sub do_replace {
my ( $header, $group, $closer, $word ) = @_;
$header. ($group =~ s/\n?^\s*\Q$word\E\s*$//mr) . $closer;
}
输出:
<Mansions \>
windows
floors
<\Mansions>
这是一个 Perl 单行代码,它使用触发器运算符 (..
) 仅对两个正则表达式匹配项中的文本进行操作。如果它匹配 /wall/
并且在开始和结束文本内,它会跳过该行。
perl -ne '/walls/ && next if /Mansions \/ .. /<\Mansions>/; print' file.txt
如果这些组没有在彼此内部分组,sed 脚本可能会起作用:
script.sed
/<Mansions \>/,/<\Mansions>/ {
/^[[:blank:]]*walls[[:blank:]]*$/ d
}
你运行它喜欢sed -Ef script.sed yourfile
。
说明
/<Mansions \>/,/<\Mansions>/ { ... }
注意内部表达式仅应用于<Mansions \>
和<\Mansions>
之间的行。当 Mansions 被分组在其他 Mansions 中时,这将不起作用。/^[[:blank:]]*walls[[:blank:]]*$/ ...
选择由单词walls
和可选的前导和尾随空格组成的行。d
表示删除这些行。
$ awk '/<\Mansions>/{f=0} f && /walls/{next} /<Mansions \>/{f=1} 1' file
<Mansions \>
windows
floors
<\Mansions>
以上内容在任何 UNIX 机器上使用任何 shell 中的任何 awk 都可以工作。
你为什么这么难?如前所述,您的问题不需要代码或正则表达式或纯香草查找和替换功能以外的任何东西。如果您的问题中隐藏了其他需要代码答案的内容,我找不到。
- 打开查找和替换。
在
Find
中使用:<Mansions \> windows walls floors <\Mansions>
在
Replace
中使用:<Mansions \> windows floors <\Mansions>
单击
Replace All
。
任务完成。