【问题标题】:Perl: Match exact word from tab-delimited filePerl:匹配制表符分隔文件中的确切单词
【发布时间】:2012-10-06 09:52:03
【问题描述】:

我有一个制表符分隔的文件(包含 2 列),格式如下:

ABA-1 (tab)           CDF@
ABA-1 (tab)           EFG
ZYA (tab)             ABA-1 this
EFG that this (tab)   ZYA

我只想匹配 /EFG/ 而不是 /EFG 那个 this/。同样,我只想匹配 /ABA-1/ 而不是 /ABA-1 this/。

以下模式不起作用:

$line=~ /^(\w*\-?\w*\@?)\t*(\w*\-?\w*\@?)$/

我尝试过使用单词边界 (\b),但它也不起作用。

关于如何解决这个问题的任何想法?任何帮助将不胜感激。非常感谢!

【问题讨论】:

  • 所以你想匹配所有字符直到找到一个空格?也喜欢CDF@
  • Tab 后面的$%^2 this 怎么样?
  • 是的,我想匹配,直到找到一个空格。
  • @RohitJain:我不明白你的第二条评论。
  • 好吧fba#$@! thsi (tab) $%^ asf -> 那么你想在这个字符串中匹配什么? -> fba#$@!$%^?

标签: regex perl csv


【解决方案1】:

您的正则表达式不起作用有几个原因。首先,您的选项卡不能是可选的,否则该行将无法正确拆分。其次,您的模式中没有任何内容可以解释 您要匹配的部分之后的可能字符,即没有任何内容与 that this 匹配。

您可以通过在每次捕获后添加 .*? 来解决第一个问题(或者,对于第二次捕获,只需删除尾随的 $ 锚点)。第二个问题只需将\t*更改为\t即可解决。

此修改适用于您的示例数据

$line =~ /^(\w*\-?\w*\@?).*?\t(\w*\-?\w*\@?).*?$/

但它不是很漂亮!

看起来您只希望所有非空格字符的字符串都直接位于制表符或行首之后

这个程序将这个想法编码为一个正则表达式

use strict;
use warnings;

my @data = (
  "ABA-1\tCDF@",
  "ABA-1\tEFG", 
  "ZYA\tABA-1 this",
  "EFG that this\tZYA",
);

for (@data) {
  my @fields = /(?:^|\t)(\S+)/g;
  print "@fields\n";
}

输出

ABA-1 CDF@
ABA-1 EFG
ZYA ABA-1
EFG ZYA

【讨论】:

    【解决方案2】:

    这将匹配由一行中的单个制表符分隔的两个单词(不包含空格):

    $line=~ /^(\w+)\t(\w+)$/
    

    更新:这将排除任何包含“ABA this”之类的行。但是,也许您只想从“ABA this”中捕获 ABA。这将为您做到这一点:

    $line=~ /^([A-Z]+)[^\t]*\t([A-Z]+)/
    

    更新:这是针对新要求的新模式。它匹配每列中的第一个非空白部分。

    $line=~ /^([^\s]+).*\t\s*([^\s]+)/
    

    【讨论】:

    • 请查看编辑后的输入文件。我已对其进行了更改,使其与我的原始文件更相似。
    • 您更新的代码不适用于 CDF@(第 1 行,第 2 列)和 ABA-1 this(第 3 行,第 2 列)。
    • @zock,我已经对其进行了测试,在这些情况下,匹配项分别返回“CDF@”和“ABA-1”。如果您没有得到这些结果,则说明您的代码存在其他问题,或者您的文件与描述的不完全一样。例如,如果您在第二列之后有一个制表符,则会导致它失败。
    【解决方案3】:
    $line=~ /^(\w+)[^\t]*\t(\w+).*$/
    

    这将仅捕获tab 之前和之后的第一个单词。

    更新:-如果你想在第一个空格之前匹配any non-space字符,那么你可以试试这个模式:-

    my $line = "ABA-1\tCDF@";
    my $line1 = "ZYA \t  ABA-1 this";
    
    if ($line=~ /^([^\s]+)[^\t]*\t\s*([^\s]+).*$/) {    
        print "$1 $2";
    }
    
    if ($line=~ /^([^\s]+)[^\t]*\t\s*([^\s]+).*$/) {    
        print "$1 $2";
    }
    

    输出:-

    ABA-1 CDF@
    ZYA ABA-1
    

    【讨论】:

    • 这不适用于在选项卡的每一侧只有一个单词的行。例如,它将第一行中的“ABA”分解为“AB”和“A”,并且只返回“AB”作为匹配项。
    • 请查看编辑后的输入文件。我已对其进行了更改,使其更类似于我的原始文件。
    • 嗯,根据你提供的模式,我要匹配34%! (标签)%^#。
    • 您更新的代码不适用于 CDF@(第 1 行,第 2 列)和 ABA-1 this(第 3 行,第 2 列)。
    • 在第二列,可以有空格,如:ABA-1(space)this.
    猜你喜欢
    • 2016-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    • 2013-10-16
    • 1970-01-01
    相关资源
    最近更新 更多