【问题标题】:Any perl standard library to check if a string contains a given substring任何用于检查字符串是否包含给定子字符串的 perl 标准库
【发布时间】:2011-11-20 04:20:26
【问题描述】:

给定一个查询,我想检查它是否包含给定的子字符串(可以包含多个单词)。但我不想穷举搜索,因为这个子字符串只能开始一个新词。

任何 perl 标准库,这样我就可以得到一些高效的东西而不必重新发明轮子?

谢谢,

【问题讨论】:

  • +1 用于询问 perl 中有用于正则表达式的模块。 ;)
  • 如果您要求非常有效的解决方案,您应该发布一些示例输入和匹配,以及一些约束,例如您应该搜索到字符串的多远。

标签: string perl standard-library


【解决方案1】:

这听起来是regular expressions 的完美工作:

if($string =~ m/your substring/) { 
    say "substring found"; 
} else { 
    say "nothing found"; 
}

【讨论】:

  • 还有can only start a fresh word 条件,这是\b 元字符用于标记单词边界的地方。
  • 不过,\b 并不是从一个新词开始的。您将 Perl 的边界概念与世界上大多数人认为的单词混为一谈。
【解决方案2】:

也许你会发现内置的index() 适合这项工作。

这是一个非常快速的子串搜索功能(实现了 Boyer-Moore 算法)。

只需通过 perldoc -f index 查看其文档即可。

【讨论】:

  • 它是否让你给搜索者提示/条件子字符串只能开始一个新词,所以它不需要从字符串中间搜索。
  • 我有大约一百万个查询要搜索大约 9k 个子字符串..所以这种优化应该有很长的路要走。
  • @p2pnode:您的问题不包含这些重要信息!
  • 好吧,你不能像使用正则表达式那样对index() 施加。它可以匹配在一个单词的中间。也许你必须像 jamessan 指出的那样制作一个适当的正则表达式。
  • @p2pnode:是什么让您认为查找词首比查找字符串更快?你的话多长时间?无论如何,单词的开头是什么?
【解决方案3】:

您可以使用这种方法:

# init
my $re = join"|", map quotemeta, sort @substrings;
$re = qr/\b(?:$re)/;

# usage
while (<>) {
  found($1) if /($re)/;
}

其中found 是找到子字符串后要执行的操作。

【讨论】:

  • 这就是 p2pnode 所说的“穷举搜索”。
  • @reinierpost:你确定吗?你做过任何测量还是只是客人?可能使用 Algorithm::AhoCorasick 会更好,但除非进行一些认真的基准测试,否则我不会说。
【解决方案4】:

我会做一个散列,键是 9000 个子字符串的第一个单词,值是一个数组,所有子字符串都带有第一个单词。如果许多字符串包含相同的第一个单词,则可以使用前两个单词。

然后对于每个查询,对于每个单词,我会查看该单词是否在哈希中,然后只需要匹配哈希数组中的那些字符串,使用索引函数从字符串中的那个点开始。

假设匹配是稀疏的,这将非常有效。每个单词进行一次哈希查找,并尽可能少地搜索潜在匹配项。

在我写这篇文章时,它让我想起了 Aho-Corasick 搜索。 (请参阅 CPAN 中的 Algorithm::AhoCorasick。)我从未使用过该模块,但该算法花费大量时间从搜索键中构建一个有限状态机,因此查找匹配项非常有效。我不知道 CPAN 实现是否处理字边界问题。

【讨论】:

    【解决方案5】:

    内置的index 函数是检查字符串是否包含子字符串的最快通用方法。

    my $find = 'abc';
    
    my $str = '123 abc xyz';
    
    if (index($str, $find) != -1) {
        # process matching $str here
    }
    

    如果index 仍然不够快,并且您知道您的子字符串可能在字符串中的哪个位置,您可以使用substr 缩小范围,然后使用eq 进行实际比较:

    my $find = 'abc';
    
    my $str = '123 abc xyz';
    
    if (substr($str, 4, 3) eq $find) {
        # process matching $str here
    }
    

    如果不使用 C,你不会比 Perl 更快。

    【讨论】:

    • 这个答案有几个问题:1)这并没有告诉您如何在许多不同的字符串上执行此操作 2)这可能是 p2pnode 穷举搜索的意思,尽管它确实不是t 3) 你可以实际上在 Perl 中变得更快(例如使用study 或文档中提到的其他技术)。
    • @reinierpost => 1) 没有给出示例数据,缺少这些数据,提供了一个基本案例。用户可以轻松地将其调整为多个字符串的循环。 2)我不知道这意味着什么,但我看不出它是如何证明不赞成引用报价的。 3) regex 永远不会比 index 或 substr/eq 快,即使字符串已经被研究过。并且大概如果用户在循环中检查字符串,研究每个字符串会比运行正则表达式要慢。总而言之,您的评论有几处问题,但感谢您的参与。
    猜你喜欢
    • 2011-11-09
    • 2013-05-18
    • 2021-12-20
    • 2018-06-14
    • 2012-04-30
    • 1970-01-01
    • 2014-11-22
    • 2013-02-05
    • 1970-01-01
    相关资源
    最近更新 更多