PERL - 正则表达式包含所有哈希键(已排序)+从文件读取中删除$ _中的空字段

时间:2011-07-01 08:32:45

标签: perl

我正在制作一个计划,我有几个问题,希望你能提供帮助:

首先,我需要访问一个文件并根据从上一步获得的索引检索特定信息,在该索引中找到要检索的索引并存储在哈希中。

我一直在寻找一种方法,将所有数组元素都包含在我可以在文件搜索中使用的正则表达式中,但是我还没有能够使它工作。最终我找到了一种有效的方法:

my @atoms = ();
my $natoms=0;

foreach my $atomi (keys %{$atome}){
push (@atoms,$atomi);
$natoms++;
}
@atoms = sort {$b cmp $a} @atoms;

然后我用它作为正则表达式:

while (<IN_LIG>){
if (!$natoms) {last;}
......
if ($_ =~ m/^\s*$atoms[$natoms-1]\s+/){
    $natoms--;  
    .....
}

有没有办法创建一个包含所有哈希键的正则表达式?它们是数字,必须进行排序。键指的是IN_LIG中的行索引,其内容类似于:

8 C5          9.9153    2.3814   -8.6988 C.ar      1 MLK        -0.1500 

密钥可在第0列(8)中找到。我添加了^和\ s +以确保它仅引用第一列。

我的第二个问题是,有时输入文件并不总是相同,并且它们在索引之前包含空格,所以当我从$ _创建数组时,我得到column0 =“”而不是column0 = 8

我不明白为什么在split命令中没有消除这个“空列”,我在删除它时遇到了一些麻烦。这就是我所做的:

@info = split (/[\s]+/,$_);

if ($info[0] eq " ") {splice (@info, 0,1);} # also tried $info[0] =~ m/\s+/

当我打印数组@info时,我得到了这个:

Array: 

Array: 8

Array: C5

Array: 9.9153

Array: 2.3814

.....

如何摆脱空栏?

非常感谢你的帮助 Merche

4 个答案:

答案 0 :(得分:2)

有一种特殊形式的split,它会删除前导和尾随空格。它看起来像这样,试试吧:

my $line = '  begins  with    spaces  and ends   with   spaces    ';
my @tokens = split ' ', $line;
# This prints |begins:with:spaces:and:ends:with:spaces|
print "|", join(':', @tokens), "|\n";

请参阅http://p3rl.org/split(或splitperldoc split的文档

此外,您的程序的第一部分可能更简单:

my @atoms = sort {$b cmp $a} keys %$atome;
my $natoms = @atoms;

但是,你对原子的最终目标是什么?如果你只是想验证你给出的原子确实在文件中,那么你不需要对它们进行排序,也不需要对它们进行计数:

my @atoms = keys %$atome;
while (<IN_LIG>){
    # The atom ID on this line
    my ($atom_id) = split ' ';
    # Is this atom ID in the array of atom IDs that we are looking for
    if (grep { /$atom_id/ } @atoms) {
        # This line of the file has an atom that was in the array: $atom_id
    }
}

答案 1 :(得分:1)

通过改进和纠正一些代码来让我们热身:

# If these are all numbers, do a numerical sort: <=> not cmp
my @atoms = ( sort { $b <=> $a } keys %{$atome} ); 
my $natoms = scalar @atoms;

无需循环键,您可以立即将它们插入阵列。您也可以立即对它们进行排序,如果它们是数字,则排序必须是数字,否则您将得到如下类型:1,11,111,2,22,222,......

$natoms可以通过@atoms中的值计数直接分配。


while(<IN_LIG>) {
    last unless $natoms;
    my $key = (split)[0]; # split splits on whitespace and $_ by default
    $natoms-- if ($key == $atoms[$natoms - 1]);
}

我不太确定你在这里做了什么,如果这是最好的方法,但是这个代码应该有用,而你的正则表达式不行。在正则表达式中,[]是元字符。默认情况下拆分会在空格上拆分$_,因此您无需明确这一点。这种拆分也肯定会删除所有空格。您的空字段很可能是空字符串'',而不是空格''。

比较两个数字的最佳方法不是使用正则表达式,而是使用等于运算符==

你的空字段应该通过拆分空格而消失。 split的默认值为split ' '

另外,如果你还没有这样做,你应该使用:

use strict;
use warnings;

它会为你节省很多麻烦。

答案 2 :(得分:0)

对于你的第二个问题,你可以使用这一行:

@info = $_ =~ m{^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)}xms;

从每行捕获9个项目(假设它们不包含空格)。

我不明白的第一个问题。

更新:我会读取文件的行并将它们用在一个散列中,其中$ info [0]作为键,[@info [1..8]]作为值。然后,您可以按索引查找条目。

my %details;
while (<IN_LIG>) {
    @info = $_ =~ m{^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)}xms;
    $details{ $info[0] } = [ @info[1..$#info] ];
}

稍后您可以查找您感兴趣的索引的详细信息并根据需要进行处理。这假定索引是唯一的(具有键的属性)。

答案 3 :(得分:0)

感谢您的所有回复。我用''尝试了拆分表单,它为我节省了几行代码。谢谢!

对于正则表达式,我发现了一些可以使所有键成为带有join和quotemeta的字符串表达式的一部分,但我无法使其工作。不过我找到了一个有效的替代方案,但我更喜欢join / quotemeta解决方案

根据某个能量阈值从文本文件中获取原子索引。之后,在IN_LIG循环中,我需要访问分子文件以获得有关所选原子的更多信息,因此我使用分子中的原子“index”来识别我必须阅读和处理的文件行。这是一个子例程,我使用原子索引和其他一些信息发送哈希值。

我为正则表达式尝试了这个:

 my $strings = join "|" map quotemeta,
 sort { $hash->{$b} <=> $hash->{$a}} keys  %($hash);

但是我做错了因为它不会占用所有键