我有一个以//#...
开头的字符串到达换行符。我已经找出了正则表达式..#([^\n]*)
。
我的问题是,如果以下条件匹配
,如何从文件中删除此行答案 0 :(得分:27)
你的正则表达式在几个方面被严重挑选:
不是专门匹配两个斜杠,而是使用..
匹配两个可能是任何东西的字符,大概是因为当你还使用斜杠时你不知道如何匹配斜杠分隔符。 (实际上,点匹配几乎任何东西,我们将在#3中看到。)
在斜线分隔的正则表达式文字//
中,您可以通过使用反斜杠保护它们来匹配斜杠,例如。 /\/\//
。然而,更好的变体是使用较长形式的正则表达式文字m//
,您可以在其中选择分隔符,例如。 m!!
。由于您使用斜杠以外的其他内容进行分隔,因此您可以在不转义它们的情况下编写它们:m!//!
。请参阅perldoc perlop。
它没有锚定到字符串的开头,因此它将匹配任何地方。使用前面的^
字符串开头断言。
你写[^\n]
以匹配“除了换行符之外的任何字符”,当有一种更简单的方法来编写它时,它只是.
通配符。它确切地说 - 匹配除换行符之外的任何字符。
您正在使用括号对匹配的一部分进行分组,但该组既没有量化(您没有指定它可以匹配任何其他次数而不是一次),您也不想保留它。所以括号是多余的。
总而言之,这就是m!^//#.*!
。但是在正则表达式的末尾放置一个未捕获的.*
(或任何带有*
量词的东西)是没有意义的,因为它永远不会改变字符串是否匹配:*
很高兴什么都不匹配。
这样就可以让你m!^//#!
。
对于从文件中删除行,正如其他人解释的那样,逐行读取并打印要保留的所有行到另一个文件。如果您不是在更大的程序中执行此操作,请使用perl的命令行开关轻松完成:
perl -ni.bak -e'print unless m!^//#!' somefile.txt
这里,-n
开关使perl围绕您提供的代码循环,它将按顺序读取您在命令行上传递的所有文件。 -i
开关(用于“就地”)表示从脚本中收集输出并用它覆盖每个文件的原始内容。 .bak
选项的-i
参数告诉perl将原始文件的备份保存在以附加.bak
的原始文件名命名的文件中。对于所有这些位,请参阅perldoc perlrun。
如果你想在一个更大的程序的上下文中这样做,最安全的方法是打开文件两次,一次用于阅读,另一次用IO::AtomicFile,另一次写入。 IO :: AtomicFile只有在成功关闭后才会替换原始文件。
答案 1 :(得分:4)
过滤掉文件中与某个正则表达式匹配的所有行:
perl -n -i.orig -e 'print unless /^#/' file1 file2 file3
-i开关后的'.orig'创建具有给定扩展名(.orig)的文件备份。如果您不需要备份,可以跳过它(只需使用-i)。
-n开关使perl为文件中的每一行执行指令(-e'...')。该行存储在$ _(这也是许多指令的默认参数,在这种情况下:print和regex匹配)。
最后,-e开关的参数说“打印该行,除非它与行开头的#字符匹配。
PS。还有一个-p开关,其行为类似于-n,除了总是打印线条(适合搜索和替换)
答案 2 :(得分:2)
正如其他人所指出的那样,如果最终目标只是删除以//#
开头的行,出于性能原因,您可能最好使用grep
或sed
:
grep -v '^\/\/#' filename.txt > filename.stripped.txt
sed '/^\/\/#/d' filename.txt > filename.stripped.txt
或
sed -i '/^\/\/#/d' filename.txt
如果您更喜欢就地编辑。
请注意,在perl中你的正则表达式将是
m{^//#}
匹配两个斜杠,后跟字符串开头的#。
请注意,您可以使用匹配运算符m{pattern}
而不是更熟悉的/pattern/
来避免“反斜杠”。尽早训练自己的语法,因为这是避免过度转义的简单方法。您可以像m{^//#}
或m%^//#%
一样有效地撰写m#^//\##
,具体取决于您要匹配的内容。力求清晰 - 正则表达式很难解释,没有可避免的反斜杠的刺痛森林,从而导致可读性降低。说真的,m/^\/\/#/
看起来像一条鳄鱼,上面有一颗碎齿和阿尔卑斯山的填充物或微小的ASCII画。
您的脚本中可能出现的一个问题是,如果将整个文件分成字符串,换行符和所有文件。要防御这种情况,请在正则表达式上使用/ m(多行)修饰符:
m{^//#}m
这允许^在换行符后在字符串和的开头匹配。您会认为有一种方法可以使用正则表达式修饰符m{^//#.*$}
,/g
和/m
来删除或匹配与/s
匹配的行。把文件写成一个字符串,但是你不想复制它(首先要问一下它为什么会被插入一个字符串的问题。)它应该是可能的,但它已经很晚了我没有看到答案。但是,一种“简单”的方法是:
my $cooked = join qq{\n}, (grep { ! m{^//} } (split m{\n}, $raw));
即使在原始字符串$raw
上创建副本而不是就地编辑。
答案 3 :(得分:1)
你真的不需要perl。
sed '/^\/\/#/d' inputfile > outputfile
我< 3 sed。
答案 4 :(得分:0)
逐行读取文件,只将这些行写入与正则表达式不匹配的新文件。 你不能只删除一行。
答案 5 :(得分:0)
它是从一条线的开头开始还是可以出现在任何地方?如果前者/旧/新是你想要的。如果是后者,我将不得不弄明白。我怀疑可以以某种方式使用反击。
答案 6 :(得分:0)
我不认为你的正则表达式是正确的。
首先你需要从^开始,否则它会在线上的任何地方匹配这个模式。
其次,..
应为\/\/
,否则它将匹配任意两个字符。
^\/\/#[^\n]*
可能就是你想要的。
然后执行EricSchaefer所说的并逐行读取文件,只写不匹配的行。
-
BMB
答案 7 :(得分:0)
尝试以下方法:
perl -ne 'print unless m{^//#}' input.txt > output.txt
如果您使用的是Windows,则需要双引号而不是单引号。
你可以用grep
做同样的事情grep -v -e '^//#' input.txt > output.txt
答案 8 :(得分:0)
迭代文件中的每一行,如果匹配模式,则跳过该行:
my $fh = new FileHandle 'filename' or die "Failed to open file - $!"; while (my $line = $fh->getline) { next if $line =~ m{^//#}; print $line; } close $fh;
这将打印文件中的所有行,但以'//#'。
开头的行除外