【问题标题】:Trying to extract unique strings from a text file in Perl尝试从 Perl 中的文本文件中提取唯一字符串
【发布时间】:2018-10-12 09:31:27
【问题描述】:

我在学习 perl 5 天时遇到了这个问题。 尝试使用正则表达式从文件中提取某个字符串并将这些字符串置于苛刻的环境中并仅打印出唯一值,例如文本文件包含如下字符串:

             "placement Z  F97342" 
             "placement Z  F97342"
             "placement d  F97342"
             "placement g  F97342" 
             "placement Z  F97342" 

预期输出:

            "placement Z  F97342"
            "placement d  F97342"
            "placement g  F97342"

下面是我的代码,但它给了我“placement Z”重复的行

             open(FHR, "<test.txt") or die "Cannot open file $!";

            while (<FHR>){

            chomp($_);
            $_ =~/placement/g;

            print "$_\n";

            }

有什么帮助吗?

【问题讨论】:

  • 欢迎使用 Stack Overflow 和 Perl 标签。请花点时间阅读How to Asktour。当询问有关编程的问题时(不仅在这里,而且在一般情况下),尽可能精确是很重要的。您的问题包含很多看起来很奇怪的空格。我已经修复了一些布局问题,但我不知道您的输入文件中是否真的包含所有这些空白空间,或者您是否只是不知道 markdown 是如何工作的。请edit您的问题并使输入和预期输出看起来完全像您的真实数据。还请附上您的完整、真实的代码。谢谢
  • 你能解释一下为什么这两行被认为是相同的:` "placement Z F97342" /placement Z F97342"` 一个有两个双引号,另一个只有一个双引号。
  • 您说您正在尝试提取字符串并将其放入哈希中。但是您的代码不会尝试这些事情。到目前为止,它所做的只是打印所有包含单词 placement 的行。您需要更具体地说明您需要帮助的内容。例如,您还没有告诉我们有关该哈希的信息。匹配是键还是值?你想数点什么吗?为什么是哈希?同样,您需要尽可能精确。编程中没有半真半假。
  • 另外,如果您只想删除重复项,请参阅 Perl 常见问题解答“如何从列表或数组中删除重复元素”:perldoc.perl.org/…
  • 好吧,可能我的表述有误。我只想获取字符串的唯一值。

标签: regex perl


【解决方案1】:

我认为你误解了很多事情。你正在做一个正则表达式匹配,但实际上并没有对结果做任何事情。

你怎么看:

        $_ =~/placement/g;

在做什么? (因为现在的答案是“什么都没有”)。

同样——你“只是”打印$_,所以你实际上只是打印文件中的每一行。

您需要在什么级别测试重复项?它是“整行”还是只是“展示位置”ID,还是紧随其后的“数字”?

但如果您需要测试重复项,您需要的是哈希。

这样的事情可以解决问题:

#!/usr/bin/env perl

use strict;
use warnings;

open( my $input, '<', "test.txt" ) or die "Cannot open file $!";

my %seen; 

while (my $line = <$input>) {
   print $line unless $seen{$line}++;
}

还有:

  • 使用打开 3 个参数的词法文件句柄是一种很好的风格。我的例子反映了这一点。
  • 获取perltidy 并使用它。 perltidy -pbp 会将您的代码缩进并格式化为普遍接受的标准。 (您可以根据自己的喜好自定义 - 格式/缩进可以是您喜欢的任何内容,只要它一致)。
  • 如果您所做的只是手动重新插入换行符,则无需chomp
  • 您应该始终使用use strict;use warnings;

如果您想更有选择性地选择要测试重复的行的哪个位,您可以使用正则表达式捕获子元素。比如说——只有“安置信”很重要:

#!/usr/bin/env perl

use strict;
use warnings;

open( my $input, '<', "test.txt" ) or die "Cannot open file $!";

my %seen; 

while ( <$input>) {
   my ( $placement_id ) = m/placement (\d+)/;
   print unless $seen{$placement_id}++;
}

注意这里 - 我没有指定 &lt;$input&gt; 的内容 - 它设置为 $_,但我觉得作为一个风格点,你应该避免在代码中使用 $_ - 如果你要去的话,命名它使用它。

这是因为m// 正则表达式匹配和print 都默认在$_ 上操作,即“当前行”。右侧正则表达式中的捕获括号用于填充$placement_id - 但请注意您需要左侧的括号,否则$placement_id_ 将只是一个'true/ false' 模式是否匹配的结果。

【讨论】:

  • 这里$placement_id在哪里初始化?
  • 它根本没有被初始化——这在perl 中是一个毫无意义的动作。它在循环词法范围内用my 声明。因此为每一行创建一个新的“版本”。
【解决方案2】:

在这种情况下,确实不需要显式打开文件句柄。 Perl 将自动打开在命令行中给出名称的任何文件,您可以使用空文件输入运算符 (&lt;&gt;) 读取它们的数据。

所以你的代码可以这么简单:

#!/usr/bin/perl

use strict;
use warnings;

my %seen;

while (<>) {
  print unless $seen{$_}++;
}

如果这段代码在一个名为filter的文件中,你可以这样称呼它:

$ filter test.txt

【讨论】:

    【解决方案3】:

    使用 Perl 单行代码

    > cat file.txt
                 "placement Z  F97342"
                 "placement Z  F97342"
                 "placement d  F97342"
                 "placement g  F97342"
                 "placement Z  F97342"
    > perl -ne  '{ print "$_" unless $data{$_}++; } ' file.txt
                 "placement Z  F97342"
                 "placement d  F97342"
                 "placement g  F97342"
    >
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-06
      • 1970-01-01
      • 1970-01-01
      • 2021-12-25
      • 1970-01-01
      • 2019-07-18
      • 2011-10-09
      相关资源
      最近更新 更多