Regex 使用Perl正则表达式解析以制表符分隔的文件

Regex 使用Perl正则表达式解析以制表符分隔的文件,regex,perl,Regex,Perl,我试图弄清楚如何使用正则表达式,以便能够从选项卡分隔的文本文件中“提取”特定文本,并对下面的文件执行操作 我有一个以下格式的文件: #HEADER_IGNORE HEADING1 HEADING2 HEADINGN Some Text Here value value2 value3 SOME_TEXTHERE x z Some More Text Here

我试图弄清楚如何使用正则表达式,以便能够从选项卡分隔的文本文件中“提取”特定文本,并对下面的文件执行操作

我有一个以下格式的文件:

#HEADER_IGNORE        HEADING1     HEADING2      HEADINGN
Some Text Here        value        value2        value3
SOME_TEXTHERE         x                          z
Some More Text Here   A            B             
我希望能够提取第一个“列”。本质上,我希望获取第一个选项卡之前的所有文本,以便正则表达式能够提取:

Some Text Here
SOME_TEXTHERE
Some More Text Here
我尝试使用下面的正则表达式,但没有任何运气

/(\W\s)*\t$/
现在,我希望能够做的第二件事是判断是否有任何行x列引用缺少值。即,在上面的示例文件中,行id
SOME_text here
缺少
HEADING2
的值。可以有任意数量的行ID和列


提前谢谢

经典方法是
chomp
每行删除行终止符,然后
split/\t/
提取所有字段值的列表

chomp;
my @fields = split /\t/;
my $field1 = $fields[0];
但是,如果您确定只需要第一列,那么最简单的方法是在行首找到所有非制表符的字符

考虑到你的第二个要求,第一个是最好的。这取决于“缺少值”的含义,但只要所有制表符分隔符都存在,就可以通过写入来检查以确保行具有给定数量的字段

my $n = grep /\S/, @fields;
warn "Missing field" unless $n == 4;
或者,如果您想发现缺少哪个字段,那么

my @missing = map { $fields[$_-1] !~ /\S/ } 1 .. 4;
warn "Missing field $missing[0]" if @missing;

我非常喜欢哈希,所以我会使用哈希。
由于如果数组中的最后一个元素丢失,
拆分
无效,因此如果最后一个元素是
\t
,我们必须手动添加一个空字符串(这样丢失的列将成为空字符串)

例如,通过检查if
$rows{SOME_texthhere}[1]eq”“

#/usr/bin/perl
严格使用;
使用警告;
chomp(我的$first_line=);
my$length=标量(拆分/\t/,$first\u行);
我的%行;
而(){
咀嚼;
my@row=split/\t/;
按@行“,”表示1..$length-标量@行;
#假设总是有一个行ID
my$id=shift@row;
$rows{$id}=[@row];
}
foreach my$rowID(键%rows){
对于(my$i=0;$i<@{$rows{$rowID}};$i++){
#列1是id
printf“在%s\n中缺少列#%d”,$i+1,$rowID
如果$rows{$rowID}[$i]eq”“;
}
}

您不按制表符拆分有什么原因吗?也许您应该使用
Text::CSV
。我尝试过按制表符拆分,但我只是将整行拆分为一个数组。我开始沿着这条路走,然后它似乎变得复杂了,因为我不一定能够跟踪第一个“列”中的文本,因为可能有N列。@user2402135第一个字段将是第一个字段,无论您使用split还是regex,不管你有多少列或者缺少多少列,你到底为什么要为一个已经很好解决的问题编写代码呢?使用已经编写、测试和调试的现有代码。文本::CSV模块将为您完成这一切。感谢您的评论。关于你答案的第一部分,请
my$field1=$fields[0]不只是在这里给我
一些文本
?对于第二个问题的解决方案,我不知道会有多少列。文件中可能有N列。“缺失值”指的是空白值。i、 e.没有任何文本。Thanks@user2402135:是的,对于数据文件的第二行,您将在此处获得一些文本
。如果制表符分隔符的数量总是正确的,那么您可以使用
/\S/
检查
@字段的每个值,如果有任何内容,则为true;如果字段包含任何非空格字符,则为false。如何调整代码以使,使用文本文件中的第一行,即
#HEADER#u IGNORE HEADING1 HEADING2 HEADINGN
,计算有3个“列”(IGNORE
#HEADER#u IGNORE
),然后使用这样一个事实,即因为我有3个“列”,所以文件中的每一行必须有3个值,这些值由制表符分隔。因此,如果我有一个有8个“列”的文件,它将以相同的方式工作,并迭代其余的行,对于每个rowID,8个“列”将有8个非空值。谢谢我修改了代码,以便它(可能)做您想要的事情,但在我看来,我觉得它太依赖于输入的正确性了。当然,这取决于您是否可以信任输入。
my @missing = map { $fields[$_-1] !~ /\S/ } 1 .. 4;
warn "Missing field $missing[0]" if @missing;
#!/usr/bin/perl

use strict;
use warnings;

chomp(my $first_line = <STDIN>);
my $length = scalar(split /\t/, $first_line);

my %rows;
while (<STDIN>) {
    chomp;
    my @row = split /\t/;
    push @row, "" for 1..$length - scalar @row;
    # Assuming there's ALWAYS a row ID
    my $id = shift @row;
    $rows{$id} = [@row];
}

foreach my $rowID (keys %rows) {
    for (my $i = 0; $i < @{$rows{$rowID}}; $i++) {
        # Column 1 being the id
        printf "missing column #%d in %s\n", $i + 1, $rowID
            if $rows{$rowID}[$i] eq "";
    }
}