【问题标题】:Calculating occurrences of the word in the text计算文本中单词的出现次数
【发布时间】:2014-01-24 06:07:24
【问题描述】:

我有一个文本,我想在其中计算短语“lorem ipsum dolor”的出现次数。

Lorem ipsum dolor 坐在一起,consectetur adipiscing elit。 Ipsum lorem dolor Curabitur ac risus nunc。 Dolor ipsum lorem

即使搜索短语以不同的顺序编写,算法也应该计算出现次数。我已经强调了预期的结果。有没有比使用正则表达式和所有可能的组合更好的方法来实现这一点?

在这种情况下,结果应该等于 3

  • Lo​​rem ipsum dolor
  • Ipsum lorem dolor
  • Dolor ipsum lorem

短语大约有 3-4 个单词,字符串将是网页的内容。

【问题讨论】:

    标签: php regex algorithm


    【解决方案1】:

    注意:也适用于“Lorem ipsum dolor dolor”。

    大家晚上好。我想出了另一种技术。这个对 Mark Ba​​ker 所做的使用了一种不同的方法,我非常感谢。此外,查看内存使用情况

    简而言之,它需要匹配的基本字符串(lorem ipsum dolor),然后将其打乱为所有可能的组合(在本例中为 3!= 6)。

    此外,所有这 6 个字符串组合然后被添加到用于匹配 substr_count 的数组中。我也在使用shuffle()in_arrayarray_push

    代码是不言自明的,如果你好奇,这里是我的IDEONE。这是 Mark Ba​​ker 在IDEONE 上的解决方案。它们都占用相同的时间和内存,我的解决方案缩短了 4 行,如果不是更优雅的话:)

    <?php
    
        $string = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ipsum lorem dolor Curabitur ac risus nunc. Dolor ipsum lorem.';
    
    //convert main string to lowercase to have an even playing field
        $string2 = strtolower($string);
        $substring = 'lorem ipsum dolor';
    
    //add the first lorem ipsum dolor to launch the array 
        $arr = array($substring);
    
    //run until the array is full with all possible combinations i.e. 6 (factorial of 3)
        for ($i=0; $i<=20; $i++) {
            $wordArray = explode(" ",$substring);
            shuffle($wordArray);
            $randString= implode(" ",$wordArray);
    
    //if random string isn't in the array, then only you push the new value 
            while (! (in_array($randString,$arr)) ) {
                array_push($arr,$randString);
            }
    
        }
    
    //var_dump($arr);
    
    //here, we do the matching, and this is pretty self explanatory
        $n = sizeof($arr);
        for ($q=0; $q<=$n; $q++) {
            $sum += substr_count($string2,$arr[$q]);
        }
    
        echo "Total occurances: ".$sum;
    
    ?>
    

    内存使用

    正如您已经看到的那样,Mark 的代码在 +2 次让我失望,但由于该程序的性质以及相关的数据复杂性,差异非常微不足道。显然,考虑到程序的复杂性,差异可能很大,但事实就是如此。

    【讨论】:

    • 但是,您的代码确实给出了通知和警告,并且您的行数方法相当虚伪
    • 是的,这些是可以修复的小警告。我只是想证明它可以以另一种方式完成,我花了相当多的时间来研究它,因此想到了分享。另外,我不计算行数?
    • 什么时候行越少越好?
    【解决方案2】:

    你可以试试正则表达式:

    /(?:(?:(?:lorem|ipsum|dolor)\s?)+)/gi
    

    preg_match_all 然后计算匹配的数量。从您的示例中,您应该得到3 matches


    我不太擅长算法,也不太擅长 PHP,但尝试...

    <?php
    
    $string = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ipsum lorem dolor Curabitur ac risus nunc. Dolor ipsum lorem.';
    
    $lower_string = strtolower($string);
    
    $text = array('lorem', 'ipsum', 'dolor');
    
    $perms = AllPermutations($text);
    $result = 0;
    foreach ($perms as $piece) {
        $phrase = join(' ', $piece);
        $result += substr_count($lower_string, $phrase);
    }
    
    # From http://stackoverflow.com/a/12749950/1578604
    function AllPermutations($InArray, $InProcessedArray = array())
    {
        $ReturnArray = array();
        foreach($InArray as $Key=>$value)
        {
            $CopyArray = $InProcessedArray;
            $CopyArray[$Key] = $value;
            $TempArray = array_diff_key($InArray, $CopyArray);
            if (count($TempArray) == 0)
            {
                $ReturnArray[] = $CopyArray;
            }
            else
            {
                $ReturnArray = array_merge($ReturnArray, AllPermutations($TempArray, $CopyArray));
            }
        }
        return $ReturnArray;
    }
    
    echo $result;
    ?>
    

    ideone demo

    【讨论】:

    • OP提到Is there any better way to achieve that than using regular expression with every possible combination?
    • @ShankarDamodaran 呵呵,看来我没注意。我觉得奇怪的是他们用正则表达式标记了这个问题。
    • 看看我对php内置解决方案的回答。
    • @Anyone 您的答案不是正确答案。这是一个仅限链接的答案。
    • @ShankarDamodaran 更新了答案以包含非正则表达式解决方案。
    【解决方案3】:
    $haystack = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ipsum lorem dolor Curabitur ac risus nunc. Dolor ipsum lorem.';
    $needle = 'Lorem ipsum dolor';
    
    $hayWords = str_word_count(
        strtolower($haystack), 
        1
    );
    $needleWords = str_word_count(
        strtolower($needle), 
        1
    );
    $needleWordsCount = count($needleWords);
    
    $foundWords = array_intersect(
        $hayWords, 
        $needleWords
    );
    
    $count = array_reduce(
        array_keys($foundWords),
        function($counter, $item) use ($foundWords, $needleWordsCount) {
            for($i = $item; $i < $item + $needleWordsCount; ++$i) {
                if (!isset($foundWords[$i]))
                    return $counter;
            }
            return ++$counter;
        },
        0
    );
    
    var_dump($count);
    

    【讨论】:

    • 这太棒了。谢谢!
    • 在您获得 lorem ipsum dolor dolor 之前效果很好 - 但我们只是变得愚蠢! +1 这个答案和它一样优雅
    • @GrahamRitchie:我的也适用于 lorem ipsum dolor dolor :)
    • 此代码将返回计数为 4 的“lorem ipsum dolor dolor”,这在技术上是错误的:它同时计算“lorem ipsum dolor”和“ipsum dolor dolor”,后者是'无效(尽管“lorem ipsum dolor lorem”会被正确计为 2)......但这些组合的可能性相当小
    【解决方案4】:

    我想你正在寻找这个:http://nl1.php.net/substr_count

    $text = 'This is a test';
    echo strlen($text); // 14
    
    echo substr_count($text, 'is'); // 2
    
    // the string is reduced to 's is a test', so it prints 1
    echo substr_count($text, 'is', 3);
    
    // the text is reduced to 's i', so it prints 0
    echo substr_count($text, 'is', 3, 3);
    
    // generates a warning because 5+10 > 14
    echo substr_count($text, 'is', 5, 10);
    
    
    // prints only 1, because it doesn't count overlapped substrings
    $text2 = 'gcdgcdgcd';
    echo substr_count($text2, 'gcdgcd');
    

    【讨论】:

    • 这也只会返回 1 个结果。 “即使搜索短语以不同的顺序编写,算法也应该计算出现次数。”
    • 此外,您可以将针头和干草堆都放入 strtolower (或上层,如果您愿意)并比较“不区分大小写”
    • @estshy,如果我理解正确,您想连续匹配这 3 个单词?
    • @Anyone 请看看我的问题,我添加了一些信息,可以帮助您更好地理解问题。
    • 是的,我明白了。在那种情况下,我会推荐杰瑞的答案,祝你好运!
    猜你喜欢
    • 1970-01-01
    • 2012-12-08
    • 1970-01-01
    • 2018-08-25
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    相关资源
    最近更新 更多