【问题标题】:How do I extract lines between two strings如何提取两个字符串之间的线
【发布时间】:2013-11-12 12:28:18
【问题描述】:

我是 perl 的绝对初学者,我试图在不同行的 2 个字符串之间提取文本行,但没有成功。看起来我在我的代码中遗漏了一些东西。代码应该打印出文件名和找到的字符串。你知道问题出在哪里吗?非常感谢您的帮助或建议。这是一个例子:

*****************
example:
START
new line 1
new line 2
new line 3
END
*****************

还有我的脚本:

use strict;
use warnings;

my $command0 = "";
opendir (DIR, "C:/Users/input/") or die "$!";
my @files = readdir DIR;
close DIR;
splice (@files,0,2);

open(MYOUTFILE, ">>output/output.txt");
foreach my $file (@files) {
    open (CHECKBOOK, "input/$file")|| die "$!";
    while ($record = <CHECKBOOK>) {
        if (/\bstart\..\/bend\b/) {
            print MYOUTFILE "$file;$_\n";
        }
    }
    close(CHECKBOOK);
    $command0 = "";
}
close(MYOUTFILE);

【问题讨论】:

    标签: perl


    【解决方案1】:

    我想你在这里尝试使用触发器,它可能对你的输入很有效,但是你写错了:

    if (/\bstart\..\/bend\b/) {
    

    触发器(范围运算符)使用两个语句,由..... 分隔。你想要的是两个正则表达式与..:

    if (/\bSTART\b/ .. /\bEND\b/) 
    

    当然,你也想匹配大小写(大写),或者使用/i修饰符来忽略大小写。您甚至可能希望使用行首锚^ 仅匹配行首,例如:

    if (/^START\b/ .. /^END\b/)
    

    你还应该知道,你的整个程序都可以用单行代替,比如

    perl -ne 'print if /^START\b/ .. /^END\b/' input/*
    

    唉,这只适用于 linux。 Windows 中的 cmd shell 不会 glob,因此您必须手动执行此操作:

    perl -ne "BEGIN { @ARGV = map glob, @ARGV }; print if /^START\b/ .. /^END\b/" input/*
    

    如果无论您做什么都无法打印整个文件,我认为问题出在您的输入文件上。所以花点时间研究一下,确保它是你认为的那样,例如:

    perl -MData::Dumper -e"$Data::Dumper::Useqq = 1; print Dumper $_;" file.txt
    

    【讨论】:

    • 感谢您的帮助。我根据您上面的建议进行了更改,但每次运行脚本时,它都会打印出整个文件,而不是仅在 START 和 END 字符串之间的行。它仅在 START 和 END 字符串是文件中整个文本的边界时才有效,如果我在 START 之前和 END 之后有一些东西,它会打印整个文件。知道为什么吗?
    • 好吧,你使用$record = &lt;CHECKBOOK&gt;,然后永远不要使用$record,这应该意味着你有很多错误,并且不应该打印任何行。至于为什么所有的行都打印出来,我不知道。听起来好像您正在单行读取文件。
    • 您对 $record 的看法是正确的。我将其更改为: if ($record =~/\start\b/ .. /^end\b/) { $command0 = $record; $找到= 1; } if ($found==1) { print MYOUTFILE "$file;$command0\n"; $找到= 0; } ....但它仍然打印所有内容:(
    • 您未能理解触发器运算符的工作原理。阅读perldoc perlop。对于 if (/foo/ .. /bar/) 之类的语句,该语句返回 false,直到找到 foo。然后它返回真,直到找到bar。这就是运营商的重点,所以不要使用一些愚蠢的$found 标志。
    • 正则表达式中的 \s 匹配空格,而不是 s。除非您知道自己需要它们,否则请停止添加额外的 \。您也没有使用 /i 或正确的大小写。
    【解决方案2】:

    如果您要匹配多行字符串,您可能需要告诉正则表达式:

    if (/\bstart\..\/bend\b/s) {
    

    注意正则表达式后面的s

    Perldoc 说:

    • s

    将字符串视为单行。即改“.”。匹配任何 任何字符,甚至是换行符,通常它不会 匹配。

    【讨论】:

    • 我认为中间有..的东西应该是触发器,即/\bstart\b/ .. /\bend\b/
    • 你认为他为什么匹配一个多行字符串?他显然是在尝试使用触发器运算符。
    猜你喜欢
    • 2019-10-26
    • 2021-01-17
    • 2019-10-25
    • 1970-01-01
    • 1970-01-01
    • 2019-10-10
    • 2020-10-15
    • 1970-01-01
    相关资源
    最近更新 更多