【问题标题】:Count unique appearance of substring in a list of words without knowing the substr?在不知道子字符串的情况下计算单词列表中子字符串的唯一外观?
【发布时间】:2012-06-26 22:13:00
【问题描述】:

*我尝试计算单词列表中子字符串的唯一出现次数* 因此,检查单词列表并检测任何单词中是否有基于多次出现的最小字符的子字符串并计算它们。我不知道任何子字符串。

这是一个可行的解决方案,您知道子字符串,但如果 您不知道怎么办? 单词所基于的字符数最少。

将查找“Book”是单词的子字符串的所有单词。有下面的php函数。

想要的结果:

book count (5)
stor count (2)

【问题讨论】:

  • 这对 preg_match 无效。看看后缀树/数组。
  • 您是否正在尝试查找您从中获得的子字符串的出现次数,例如一个文件,即它在运行时知道,但在程序写入时不知道。或查找字符串中所有重复的子字符串。或者别的什么。
  • 所以您正在寻找最长的公共唯一子串?这是一项相当复杂的任务和科学研究课题。希望我能找到好的参考...
  • @deceze 是的,我想根据 MINIMUM_CHAR 查找上传的单词列表中出现的唯一子字符串的数量。
  • 到底是什么问题?您发布了代码 - 它的行为不符合您的要求吗?

标签: php count preg-match substring preg-match-all


【解决方案1】:

给定一个长度为 100 的字符串

book bookstore bookworm booking book cooking boring bookingservice.... ok
0123456789...                                                     ... 100

您的算法可能是:

调查来自不同起点和子串长度的子串。 您从 0 开始,长度为 1-100 的所有子字符串,因此:0-1, 0-2, 0-3,... 并查看这些子字符串中的任何一个是否在整个字符串中出现多次。 从增加的位置开始遍历字符串,搜索从 1 开始的所有子字符串,即 1-2、1-3、1-4、... 等等,直到达到 99-100。

保留所有子字符串及其出现次数的表格,您可以对它们进行排序。

您可以通过指定最小和最大长度来进行优化,这会显着减少搜索次数和命中率。此外,一旦您找到一个子字符串,就将它们保存在一组搜索到的子字符串中。如果再次遇到子字符串,请跳过它。 (即您已经计算过的 book 的命中数,当您点击下一个 booksubstring 时不应再次计算)。此外,您永远不必搜索长度超过总字符串一半的字符串。

对于示例字符串,您可能会针对字符串的唯一性运行附加测试。 你会有

o              x ..
oo             x  7
bo             x  7
ok             x  6 
book           x  5
booking        x  2
bookingservice x  1

忽略短于 3 的刺(并且长于总文本字符串的一半),你会得到

book           x  5
booking        x  2
bookingservice x  1

这已经是一个相当合理的结果了。

[edit] 这显然会查看所有字符串,而不仅仅是自然词。

[edit] 通常我不喜欢为 OP 编写代码,但在这种情况下,我自己有点感兴趣:

$string = "book bookshelf booking foobar bar booking ";
$string .= "selfservice bookingservice cooking";

function search($string, $min = 4, $max = 16, $threshhold = 2) {
    echo "<pre><br/>";
    echo "searching <em>'$string'</em> for string occurances ";
    echo "of length $min - $max: <br/>";

    $hits = array();
    $foundStrings = array();

    // no string longer than half of the total string will be found twice
    if ($max > strlen($string) / 2) {
        $max = strlen($string);
    }

    // examin substrings:
    // start from 0, 1, 2...
    for ($start = 0; $start < $max; $start++) {

        // and string length 1, 2, 3, ... $max
        for ($length = $min; $length < strlen($string); $length++) {

            // get the substring in question, 
            // but search for natural words (trim)
            $substring = trim(substr($string, $start, $length));

            // if substring was not counted yet, 
            // add the found count to the hits
            if (!in_array($substring, $foundStrings)) {
                preg_match_all("/$substring/i", $string, $matches);
                $hits[$substring] = count($matches[0]);
            }
        }
    }

    // sort the hits array desc by number of hits
    arsort($hits);

    // remove substring hits with hits less that threshhold
    foreach ($hits as $substring => $count) {
        if ($count < $threshhold) {
            unset($hits[$substring]);
        }
    }

    print_r($hits);
}

search($string);

?>

cmets 和变量名应该让代码自己解释。在您的情况下,$string 将用于读取文件。此示例将输出:

searching 'book bookshelf booking foobar bar booking selfservice 
bookingservice cooking' for string occurances of length 4 - 16: 
Array
(
    [ook] => 6
    [book] => 5
    [boo] => 5
    [bookin] => 3
    [booking] => 3
    [booki] => 3
    [elf] => 2
)

让我知道你是如何实现它的:)

【讨论】:

  • 谢谢,我现在看到这是以一种不复杂的体面方式实现这一目标的唯一方法。您能否提供一个简单的函数或一些代码来展示这一点?我看到了这个概念,但并没有完全转化为代码方面
  • 您不必担心搜索模式中的长度,然后您可以丢弃最大长度,并且按订单长度更快。
  • 使用一些示例 php 代码查看我的编辑。有趣的问题:)
【解决方案2】:

这是我的第一个近似值:未完成、未经测试、至少有 1 个错误,并且是用 eiffel 编写的。好吧,我不会为你做所有的工作。

deferred class
    SUBSTRING_COUNT
feature
    threshold : INTEGER_32 =5

    biggest_starting_substring_length(a,b:STRING):INTEGER_32
        deferred
    end

    biggest_starting_substring(a,b:STRING):STRING
    do
        Result := a.substring(0,biggest_starting_substring_length(a,b))
    end

    make_list_of_substrings(a,b:STRING)
    local
        index:INTEGER_32
        this_one: STRING
    do
        from
            a_index := b_index + 1
        invariant
            a_index >=0 and a_index <= a.count
        until
            a_index >= a.count
        loop
            this_one := biggest_starting_substring(a.substring (a_index, a.count-1),b)
            if this_one.count > threshold then
                list.extend (this_one)
            end
        variant
            a.count - a_index
        end
    end -- biggest_substring

    list : ARRAYED_LIST[STRING]

end

【讨论】:

  • 谢谢 Richard 我看了一下,我的目标不是来自某人的功能性 sn-p,只是为了讨论是否可行。以前从未听说过埃菲尔。必须看看您使用的那些功能是否可用于php..
  • 我没有使用很多函数,只是 {STRING}.substring(它需要一个字符串和两个数字,第一个索引和所需子字符串的最后一个索引),{LIST}.extend(它添加一个项目到列表的结尾),{STRING}.count )它告诉你一个字符串有多长)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多