【问题标题】:Match different variant of a word using regex Perl使用正则表达式 Perl 匹配单词的不同变体
【发布时间】:2013-08-04 01:49:49
【问题描述】:

我在单个空格字符处拆分句子,然后将这些术语与哈希键进行匹配。只有当术语 100% 相似时,我才会得到匹配,并且我正在努力寻找一个完美的正则表达式,它可以匹配多个相同单词的出现。例如。让我们考虑一下我有一个术语“拮抗剂”,现在它与术语“拮抗剂”完全匹配,但无法与拮抗剂、拮抗剂或前拮抗剂、水拮抗剂等匹配。我还需要一个正则表达式来匹配诸如 MCF 之类的词的出现-7 与 MCF7 或 MC-F7 静音特殊字符等效果。

这是我到现在为止的代码; thr 评论部分是我苦苦挣扎的地方。

(注意:散列中的术语是词根形式)。

    use warnings;
    use strict;
    use Drug;
    use Stop;
    open IN,  "sample.txt"   or die "cannot find sample";
    open OUT, ">sample1.txt" or die "cannot find sample";

    while (<IN>) {
        chomp $_;
        my $flag = 0;
        my $line = lc $_;
        my @full = ();
        if ( $line =~ /<Sentence.*>(.*)<\/Sentence>/i ) {
            my $string = $1;
            chomp $string;
            $string =~ s/,/ , /g;
            $string =~ s/\./ \. /g;
            $string =~ s/;/ ; /g;
            $string =~ s/\(/ ( /g;
            $string =~ s/\)/ )/g;
            $string =~ s/\:/ : /g;
            $string =~ s/\::/ :: )/g;
            my @array = split / /, $string;

            foreach my $word (@array) {
                chomp $word;
                if ( $word =~ /\,|\;|\.|\(|\)/g ) {
                    push( @full, $word );
                }
                if ( $Stop_words{$word} ) {
                    push( @full, $word );
                }

                if ( $Values{$word} ) {
                    my $term = "<Drug>$word<\/Drug>";
                    push( @full, $term );
                }
                else {
                    push( @full, $word );
                }

                # if($word=~/.*\Q$Values{$word}\E/i)#Changed this
                # {
                # $term="<Drug>$word</$Drug>";
                # print $term,"\n";
                # push(@full,$term);
                # }
            }
        }
        my $mod_str = join( " ", @full );
        print OUT $mod_str, "\n";
    }

【问题讨论】:

  • 你应该尽量让你的问题更简洁。
  • 请提供您的sample.txt。通常,对于您的“特殊字符”情况,最简单的方法是在开始之前将它们从输入中删除。
  • sample.txt 文件是科学文本文件,我不能去掉这些字符,因为这会改变一些术语的含义
  • @TLP : 让我知道你不清楚哪一部分
  • 我不认为正则表达式可以做你想做的事。对我来说听起来像是XY problem。考虑String::Compare

标签: regex perl


【解决方案1】:

我需要一个正则表达式来匹配出现的单词,例如 MCF-7 和 MCF7 或 MC-F7

最直接的方法就是去掉连字符,即

my $ignore_these = "[-_']"
$word =~ s{$ignore_these}{}g;

我不确定你的 Value 哈希中存储了什么,所以很难说你期望发生什么

if($word=~/.*\Q$Values{$word}\E/i)

但是,我想你想要的东西是(稍微简化你的代码)

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use 5.10.0;
use Data::Dumper;

while (<>) {
    chomp $_;
    my $flag = 0;
    my $line = lc $_;
    my @full = ();
    if ( $line =~ /<Sentence.*>(.*)<\/Sentence>/i ) {
        my $string = $1;
        chomp $string;
        $string =~ s/([,\.;\(\)\:])/ $1 /g; # squished these together 
        $string =~ s/\:\:/ :: )/g;          # typo in original
        my @array = split /\s+/, $string;   # split on one /or more/ spaces

        foreach my $word (@array) {
            chomp $word;
                        my $term=$word;
                        my $word_chars = "[\\w\\-_']";
                        my $word_part  = "antagon";
                        if ($word =~ m{$word_chars*?$word_part$word_chars+}) {
                            $term="<Drug>$word</Drug>";
                        }
                        push(@full,$term); # push 

        }
    }
    my $mod_str = join( " ", @full );
        say "<Sentence>$mod_str</Sentence>";
}

这给了我以下输出,这是我对您期望的最佳猜测:

$ cat tmp.txt 
<Sentence>This in antagonizing the antagonist's antagonism pre-antagonistically.</Sentence>
$ cat tmp.txt | perl x.pl
<Sentence>this in <Drug>antagonizing</Drug> the <Drug>antagonist's</Drug> <Drug>antagonism</Drug> <Drug>pre-antagonistically</Drug> .</Sentence>
$ 

【讨论】:

    【解决方案2】:
    perl -ne '$things{$1}++while s/([^ ;.,!?]*?antagon[^ ;.,!?]++)//;END{print "$_\n" for sort keys %things}' FILENAME
    

    如果文件包含以下内容:

    he was an antagonist
    antagonize is a verb
    why are you antagonizing her?
    this is an alpha-antagonist
    

    这将返回:

    alpha-antagonist
    antagonist
    antagonize
    antagonizing
    

    以下是常规(非单行)版本:

    #!/usr/bin/perl
    use warnings;
    use strict;
    open my $in, "<", "sample.txt" or die "could not open sample.txt for reading!";
    open my $out, ">", "sample1.txt" or die "could not open sample1.txt for writing!";
    
    my %things;
    
    while (<$in>){
        $things{$1}++ while s/([^ ;.,!?]*?antagon[^ ;.,!?]++)//
    }
    
    print $out "$_\n" for sort keys %things;
    

    【讨论】:

    • if($word=~/\b\Q$Values{$word}\E(\w++)\b/i) 匹配所有内容
    • 解释你的意思。我不确定你想要什么。我刚刚更新了一些代码。我即将让它正确处理逗号等。
    • 你能在我的代码中的注释部分更新它吗?你上面解释的正是我想要的。
    • 代码现在应该可以正常工作了。我假设您正在从允许您执行perl -ne 的终端运行。您必须将FILENAME 替换为要检查的文件的名称。如果你不是从终端操作来运行我写的命令,告诉我,我会用不同的形式重写它。
    • 我没有从终端运行。请您在评论区更新。
    【解决方案3】:

    您可能想再看看您对方法的假设。在我看来,您正在寻找在单词列表一定距离内的单词。查看Levenshtein distance 公式,看看这是否是您想要的。但是请注意,计算这可能需要指数级的时间。

    【讨论】:

    • 我只是想找到一个正则表达式来匹配相同单词的不同形式,比如如果我的哈希键是协同的,它应该匹配协同、反协同等术语。
    • 好吧,从您最初的想法开始,您可以通过将 [^a-zA-Z0-9]+ 的每个匹配项替换为空字符串来去除特殊字符。此外,您可以使用您的密钥(假设您的密钥可能是可能是较长单词的简短/通用版本)针对您当前正在测试的字符串进行搜索。如果有匹配项(键在测试字符串中),那么您可能已经找到了一个匹配项。
    • +1 用于提及 Levenshtein 距离。我使用 String::Compare 完成了不同的任务,取得了不错的结果。
    • 删除术语或用空格替换 say 会改变术语的含义。例如:MC-F7。如果我这样做,MC 将是一个术语,而 F7 将是另一个术语。这使得哈希(MCF7)中的密钥难以匹配
    • 那么正则表达式不是这个任务的正确工具。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 2022-11-14
    • 1970-01-01
    相关资源
    最近更新 更多