【问题标题】:Regex to find all substrings and longest substring正则表达式查找所有子字符串和最长的子字符串
【发布时间】:2011-10-02 10:13:50
【问题描述】:

我通常会使用字符串库来做这样的事情。但我想知道是否可以使用正则表达式来完成。

我想做以下事情:给定一个搜索字符串

西雅图很棒

我想在给定的句子中找到它的所有子字符串。因此,将正则表达式应用于以下 sentence

西雅图太棒了 西雅图太棒了 太棒了 西雅图

应该给我

西雅图,西雅图太棒了,太棒了,太棒了,西雅图

一个可能有用的限制是,句子总是只有搜索字符串中出现的单词和中间的空格。

注意如果有匹配,它应该是最长的字符串。因此,就像在上面的示例中一样,匹配项不应该是单个单词,而是可能是最长的子字符串。单词之间的顺序也需要保持。这就是为什么

西雅图很棒

在上面的句子中给了我们

太棒了,是和西雅图

我不确定这样的事情是否可以用正则表达式来完成,因为它是贪婪的。对此有任何见解! 我熟悉 C# 和 Java,可以使用它们的任何一个正则表达式库。

【问题讨论】:

    标签: c# java regex


    【解决方案1】:

    我认为你不能用正则表达式来做到这一点。维基百科上有一篇关于longest common subsequence problem 的好文章。

    【讨论】:

    • 我知道但为了匹配字符。我需要在这里匹配单词,尽管我可以修改算法。正则表达式让我可以灵活地在单词之间添加更多分隔符(而不仅仅是空格)。
    【解决方案2】:

    没有好办法直接用正则表达式表达这种模式。

    您需要列出所有允许的组合:

    西雅图很棒|西雅图很棒|西雅图很棒|很棒|很棒

    或更简洁地说:

    西雅图(是(真棒)?)?|是(真棒)?|真棒

    您可以通过编程方式将输入字符串转换为这种格式。

    【讨论】:

    • 这对于任何重要的输入字符串来说很快就会变得很麻烦。
    • 正如我所说,您不必手动执行此转换。注意与后缀树的相似性。事实上,如果正则表达式的性能不够好,您可以轻松地直接创建一个基于后缀树的算法,而不是使用正则表达式。
    • @dtb - 您是在考虑单词的后缀树,还是字符的后缀树?如果是的话,你知道哪里有一个好的泛型后缀树实现?从经验来看,自己写,甚至为角色改编,都不是我所说的“容易”。 (另外,请参阅下面我的替代 impl - 它的速度非常快 - 每个搜索字符串到目标位置的比较只需一个 == 比较,加上更多的匹配项。)
    • @Ed Staub:词的后缀树。实际上,由于树只包含一个句子,因此您实际上不需要构建后缀树,而只需对句子本身进行操作即可。
    【解决方案3】:

    你能进一步描述你的问题吗?这听起来更像是一个搜索引擎,而不是简单的字符串匹配。我强烈建议查看 Apache Lucene——它有一点学习曲线,但它是一个很棒的智能搜索小工具。它处理了很多在处理搜索时遇到的问题。您可以设置命中的评分来完全按照您的描述进行。

    【讨论】:

    • 一般情况下,类似“答案”的帖子应保留为 cmets。向 OP 提出问题并提出概括性 建议(不涉及具体问题),您就是在添加评论
    【解决方案4】:

    在 Java 中,未测试。这将返回字符串列表的迭代器。每个列表都是一个匹配的子序列。 只需在要打印的列表成员之间放置空格即可。如果它被大量使用,那么 intern() 的使用可能会很糟糕。

    static Iterator<List<String>> getSequences(String squery, String starget)
    {
        List<String> query = Arrays.asList(squery.split(" "));
        for ( int i = 0; i < query.size(); i++)
            query.set(i, query.get(i).intern());
        List<String> target = Arrays.asList(starget.split(" "));;
        for ( int i = 0; i < target.size(); i++)
            target.set(i, target.get(i).intern());
    
        // Because the strings are all intern'ed, this HashSet acts like we want -
        // If two lists are the same sequence of words, they are equal.
        // It's used to remove duplicates.
        HashSet<List<String>> ret = new HashSet<List<String>>();
        for ( int qBegin = 0; qBegin < query.size(); qBegin++ )     {
            for ( int tBegin = 0; tBegin < target.size(); tBegin++ ) {
                for ( int iCursor = 0; 
                      iCursor < min(query.size()-qBegin, target.size()- tBegin); 
                      iCursor++)                {
                    if ( query.get(qBegin+iCursor)==target.get(tBegin+iCursor) )
                        ret.add(query.subList(qBegin, qBegin+iCursor+1));
                    else break;
                }
            }
        }
        return ret.iterator();
    }
    
    static int min(int a, int b) { return (a<b)? a:b; }
    

    【讨论】:

    • 这不正确有几个原因: - 它不返回不是从查询字符串开头开始的子字符串匹配 - 它不会修剪最长的子字符串。我离开它是因为实习黑客可能应该用于任何好的解决方案 - 可能使用 Guava interner 代替。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-16
    • 2012-05-12
    • 1970-01-01
    • 1970-01-01
    • 2017-07-04
    相关资源
    最近更新 更多