Perl正则表达式匹配和删除

时间:2020-03-05 18:58:03  来源:igfitidea点击:

我有一个以'//#...'开头的字符串,直到换行符。我已经找到了正则表达式,它是这个..#([^ \ n] *)

我的问题是,如果满足以下条件,如何从文件中删除此行

解决方案

回答

逐行读取文件,仅将这些行写入与正则表达式不匹配的新文件中。
我们不能只删除一行。

回答

它是从一行的开头开始还是可以出现在任何地方?如果想要旧的/旧的/新的。如果是后者,我必须弄清楚。我怀疑可以使用反向引用。

回答

我认为正则表达式不正确。

首先,我们需要以^开头,否则它将与行中任何位置的此模式匹配。

其次," .."应为" \ / \ /",否则它将与任何两个字符匹配。

^ \ / \ /#[^ \ n] *可能就是我们想要的。

然后执行EricSchaefer所说的,并逐行读取文件,只写不匹配的行。

--
胖子

回答

请尝试以下操作:

perl -ne 'print unless m{^//#}' input.txt > output.txt

如果使用的是Windows,则需要双引号而不是单引号。

我们可以使用grep进行相同的操作

grep -v -e '^//#' input.txt > output.txt

回答

遍历文件中的每一行,如果与模式匹配,则跳过该行:

my $fh = new FileHandle 'filename'
    or die "Failed to open file - $!";

while (my $line = $fh->getline) {
    next if $line =~ m{^//#};
    print $line;
}
close $fh;

这将打印文件中的所有行,但以'//#'开头的行除外。

回答

我们真的不需要perl。

sed '/^\/\/#/d' inputfile > outputfile

我<3 sed。

回答

要过滤出文件中与某个正则表达式匹配的所有行:

perl -n -i.orig -e 'print unless /^#/' file1 file2 file3

-i开关后的'.orig'创建具有给定扩展名(.orig)的文件备份。如果不需要备份,可以跳过它(只需使用-i即可)。

-n开关使perl对文件中的每一行执行指令(-e'...')。该行存储在$ _中(这也是许多指令的默认参数,在这种情况下,是print和regex匹配)。

最后,-e开关的参数表示"打印行,除非它与行开头的字符匹配。

PS。还有一个-p开关,其行为类似于-n,只是行始终被打印(便于搜索和替换)

回答

正则表达式在以下几点上被错误选择:

  • 不用专门匹配两个斜杠,而是使用" .."来匹配两个可以是任意字符的字符,大概是因为当我们还使用斜杠作为分隔符时我们不知道如何匹配斜杠。 (实际上,点几乎可以匹配任何内容,请参见#3. )在以斜杠分隔的正则表达式文字" //"中,可以简单地通过使用反斜杠来保护斜杠来匹配斜杠,例如。 / \ / \ //。然而,更好的选择是使用较长形式的正则表达式文字" m //",例如,我们可以在其中选择定界符。嗯!由于使用了除斜杠以外的其他东西作为分隔符,因此我们可以编写它们而不必转义它们:m!//!。请参见perldoc perlop。
  • 它没有锚定到字符串的开头,因此它将在任何地方匹配。在前面使用^字符串开始声明。
  • 我们写了[[^ \ n]`来匹配除换行符以外的任何字符,这是一种更简单的写法,即通配符"。"。它确实匹配除换行符以外的任何字符。
  • 我们使用括号将匹配的一部分分组,但是该分组既没有量化(我们没有指定它可以匹配除精确匹配一次以外的任何其他次数),也没有兴趣保留它。因此括号是多余的。

总的来说,这就是m!^ //#。*!。但是将未捕获的。*(或者带有*量词的任何内容)放在正则表达式的末尾是没有意义的,因为它永远不会改变字符串是否匹配: 。

这样就剩下m!^ //#!了。

至于从文件中删除该行,正如其他人所解释的那样,请逐行阅读它,然后将所有要保留的行打印回另一个文件。如果我们不在大型程序中执行此操作,请使用perls命令行开关轻松执行此操作:

perl -ni.bak -e'print unless m!^//#!' somefile.txt

在这里,-n开关使perl在我们提供的代码周围放一个循环,该代码将按顺序读取我们在命令行上传递的所有文件。 -i开关(用于就地)表示收集脚本的输出并用它覆盖每个文件的原始内容。 -i选项的.bak参数告诉perl将原始文件的备份保存在以原始文件名命名的文件中并添加.bak。有关所有这些位,请参见perldoc perlrun。

如果要在较大程序的上下文中执行此操作,安全地执行此操作的最简单方法是两次打开文件,一次用于读取,另一次使用IO :: AtomicFile打开,另一次用于写入。 IO :: AtomicFile仅在成功关闭后才替换原始文件。

回答

正如其他人指出的那样,如果最终目标只是删除以//#开头的行,出于性能原因,最好使用grep或者sed

grep -v '^\/\/#' filename.txt > filename.stripped.txt

sed '/^\/\/#/d' filename.txt > filename.stripped.txt

或者

sed -i '/^\/\/#/d' filename.txt

如果我们喜欢就地编辑。

请注意,在perl中,正则表达式为

m{^//#}

匹配两个斜杠,然后在字符串的开头加上a。

请注意,通过使用匹配运算符m {pattern}而不是更熟悉的/ pattern /,可以避免"反斜杠炎"。尽早训练这种语法,因为这是避免过度转义的简单方法。我们可以将m {^ //#}与m%^ //#%或者m#^ // \ ##一样有效,具体取决于我们要匹配的内容。力求清晰,正则表达式很难破译,而又避免了许多可避免的反斜杠破坏可读性的麻烦。严肃地说," m / ^ \ / \ /#/"看起来像是一条鳄鱼,上面有一颗缺齿的牙齿,上面是阿尔卑斯山的填充物或者微小的ASCII画。

脚本中可能出现的一个问题是,如果将整个文件都拼成字符串,换行符和所有内容。为了防止这种情况,请在正则表达式上使用/ m(多行)修饰符:

m{^//#}m

这允许^在字符串的开头和换行符之后进行匹配。我们可能会想到有一种方法可以使用正则表达式修饰符" / g"," / m"和" / s"来去除或者匹配与" m {^ //#。* $}"匹配的行'已经将文件粘贴到字符串中,但是我们不想复制它(乞求为什么首先将它粘贴到字符串中的问题。)应该可以,但是已经晚了,我没有看到答案。但是,一种"简单"的方法是:

my $cooked = join qq{\n}, (grep { ! m{^//} } (split m{\n}, $raw));

即使这样会创建一个副本,而不是对原始字符串$ raw进行就地编辑。