简体   繁体   English

是否存在可以从文件中特定的一组行中删除一行的正则表达式,Perl或sed?

[英]Is there a regex, perl, or sed that can remove one line from a particular group of lines in a file?

So for example if I have something like: 因此,例如,如果我有类似的内容:

<Mansions \>
 windows
 walls
 floors
<\Mansions>

and I want to remove lets say walls and keep the other lines there how do I do that with regex or is there a better option than regex? 我想删除让我们说的墙,并保留其他行在那里,我该如何使用正则表达式呢?还是有比正则表达式更好的选择?

So I need it to look like: 所以我需要它看起来像:

<Mansions \>
 windows
 floors
<\Mansions>

and the lines up above will still be there after I remove walls. 移除墙壁后,上方的线条仍会存在。 So the goal is to search for those group of lines in the file and remove one word and still keep the other words there and in the group. 因此,目标是在文件中搜索这些行组,并删除一个单词,而仍然保留其他单词在该行中以及该组中。

Keep in my mind I'm just changing this group in the file, not an instance of the word in the file because that would be a simpler expression. 请记住,我只是在更改文件中的该组,而不是更改文件中单词的实例,因为这将是一个更简单的表达式。

I have tried using a regex that goes: 我尝试使用正则表达式:

^(<Mansion\s*"/.*/.*">)((?:\n(?!.*(?:walls\s(floor|windows)+.*\n|</Mansion>)).*)*\n</Mansion>)$

but that is not working when I remove a single word like walls 但这在我删除单个单词如墙时不起作用

So is it possible to use regex for something like this or no? 那么是否可以将正则表达式用于这种或否?

Here's a Perl one-liner that uses the flip flop operator ( .. ) to only operate on text within two regex matches. 这是一个Perl单行代码,它使用触发器运算符( .. )仅对两个正则表达式匹配中的文本进行操作。 It skips the line if it matches /wall/ and is within the opening and closing text. 如果它匹配/wall/并且在开始和结束文本之内,则跳过该行。

perl -ne '/walls/ && next if /Mansions \\/ .. /<\\Mansions>/; print' file.txt
$ awk '/<\\Mansions>/{f=0} f && /walls/{next} /<Mansions \\>/{f=1} 1' file
<Mansions \>
 windows
 floors
<\Mansions>

The above will work using any awk in any shell on any UNIX box. 上面的命令可以在任何UNIX盒子上的任何shell中使用任何awk来工作。

In Perl you could try the following: 在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($1, $2, $3, $word)/mseg;

say $str;

sub do_replace {
    my ( $header, $group, $closer, $word ) = @_;
    $header. ($group =~ s/\n?^\s*\Q$word\E\s*$//mr) . $closer;
}

Output : 输出

<Mansions \>
 windows
 floors
<\Mansions>

If the groups are not grouped inside each other, a sed script might work: 如果这些组没有相互分组,则可以使用sed脚本:

script.sed script.sed

/<Mansions \\>/,/<\\Mansions>/ {
    /^[[:blank:]]*walls[[:blank:]]*$/ d
}

You run it like sed -Ef script.sed yourfile . 您可以像sed -Ef script.sed yourfile一样运行它。

Explanation 说明

  • /<Mansions \\\\>/,/<\\\\Mansions>/ { ... } takes care that the inner expression is only applied to lines between <Mansions \\> and <\\Mansions> . /<Mansions \\\\>/,/<\\\\Mansions>/ { ... }注意内部表达式仅应用于<Mansions \\><\\Mansions> This will not work when Mansions are grouped inside other Mansions. 当大厦合并在其他大厦内时,这将不起作用。
  • /^[[:blank:]]*walls[[:blank:]]*$/ ... selects lines that consists of the word walls with optional leading and trailings blanks. /^[[:blank:]]*walls[[:blank:]]*$/ ...选择包含单词walls以及可选的前导和尾随空白的行。
  • d means delete such lines. d表示删除这些行。

Why are you making it hard? 你为什么要加倍努力? As described your problem requires no code or regex or anything other than pure vanilla find and replace functionality. 如前所述,您的问题不需要任何代码或正则表达式,也不需要纯粹的香草查找和替换功能。 If there is something else hidden in your question that requires a code answer I can't find it. 如果您的问题中还有其他地方需要代码答案,那么我找不到。

  1. Open Find and Replace. 打开查找和替换。
  2. In Find use this: Find使用以下命令:

    <Mansions \\> windows walls floors <\\Mansions>

  3. In Replace use this: Replace使用以下命令:

    <Mansions \\> windows floors <\\Mansions>

  4. Click Replace All . 单击Replace All

Mission accomplished. 任务完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM