我在学习Perl。 我的data.txt文件包含:
Lori:James Apple
Jamie:Eric Orange
下面的代码打印第一行" Lori:James Apple"
open(FILE,'data.txt');
while(<FILE>){
print if /James/;
}
但是如何修改我的正则表达式以搜索特定字段?
例如,我想使用2个分隔符&#39; &#39;和&#39;:&#39;使每行包含3个字段并检查第一行的第3个字段是否为Apple。这相当于awk -F'[ :]' '$3 = "Lori"' data.txt
答案 0 :(得分:4)
正则表达式的一个简单方法是使用negated character class(另见in perlreftut)
open my $fh, '<', $file or die "Can't open $file: $!";
while (my $line = <$fh>)
{
my @fields = $line =~ /([^:\s]+)/g;
}
[^...]
匹配除里面列出的字符之外的任何字符(在^
之后&#34;否定&#34;)。 +
quantifier表示匹配一次或多次,因此整个模式匹配除:
和&#34;空格之外的连续字符串。&#34;有关\s
的准确说明,请参阅文档。如果您实际上只想跳过单个文字空间,请使用[^: ]
。所有这些都由()
捕获。
由于全局修饰符 /g
,搜索会继续浏览字符串,找到所有此类匹配项。由于它位于列表context 中,因此返回匹配列表,该列表已分配给@fields
数组。
人们可以随时随地挑选元素&#34;通过索引到列表($line =~ /([^:\s]+)/g)[2]
。如果我们匹配$_
,则为(/([^:\s]+)/g)[2]
。
对于初学者,我建议您仔细阅读perlreftut。
另一方面,使用split
通常更简单,更清晰my @fields = split /[:\s]/, $line;
这也使用正则表达式来分割字符串的模式。字符类不会被否定,因为它在这里指定了分隔符本身,:
或\s
(每个分隔符可以是其中之一,它们不必都是相同的)。< / p>
我现在想回答具体问题,但问题并不清楚。
它要求&#34; 检查第一行的第3个字段是否为Apple &#34;,例如可以做什么
while (<$fh>)
{
if ( (/([^:\s]+)/g)[2] eq 'Apple' ) {
# ....
}
}
但它并不清楚如何处理它。或许通过第三个领域获得第一个领域?
我建议获取一个数组,然后进行处理。可以编写一个正则表达式来直接识别和选择字段,但这更加脆弱,正则表达式本身则取决于字段的位置(和数量)。
此时我们正处于猜谜游戏中。如果您需要更多细节,请澄清。
给定的awk
代码会产生Lori James Lori
,但我不知道这是怎么回事。
答案 1 :(得分:0)
简短的回答是 - 不要。正则表达式是关于模式匹配,而不是上下文。
你可以定义一个以分隔符和字段构建的模式,但是......它不适合这项工作。
答案是使用split
然后单独处理字段。
open ( my $input, '<', 'data.txt' ) or die $!;
while(<$input>){
chomp;
my @fields = split /[\s:]/;
print if $fields[2] eq "Apple";
}
如果您愿意,可以进一步压缩,但我建议谨慎 - 以可读性为代价来压缩代码并不是一种美德。
另外 - 当我们在这里时:
open(FILE,'data.txt');
是错误的样式 - 它不会检查是否成功,它还使用全局文件句柄名称。它会好得多:
open ( my $input, '<', 'data.txt' ) or die $!;
autodie
编译指示也隐式执行此操作。