在Textblock中搜索给定关键字的最短通道

时间:2016-05-20 10:27:07

标签: php arrays regex string search

我有一项任务,我不确定如何解决问题。我有一个idead,但我不知道这是否是解决它的最好方法。

这是任务: 给定是一个文本块和一些要查找的关键字。我们需要找到一个可以找到所有单词并使用最少单词的段落。只需要考虑A-Z和a-z中的字母。

这是一个例子:
文本块:
Ein toller Beispieltext ist der Blindtext。 Er hat einpaarWörter。死了 ein Beispieltext,der einpaarWörterhatund auch noch ein paar mehr,嗯 ZeileetwasLängerzumahen。 Darüberhinausist ernurdafürda,嗯 genügendTesttextzusammenzubekommen。 Dem Text selbst macht das nicht so viel aus。 Frühereinmalmehr,als er noch nicht so selbstbewusst war。 HEUTE kennt er seine Rolle als Blindtextundfügtsichselbstbewusst ein。呃,是的 ja irgendwie wichtig。 Manchmal jedoch,ganz manchmal,weint er in der Nacht, Weil er niemals bis zum Ende gelesen wird。 Doch das hat ja jetztzumGlück 恩恩恩。

这里需要找到的词语: EIN Beispieltext DER 帕 Wörter

结果将是 Beispieltext der ein paar Wrter

通过之后也是一个可以找到所有单词的段落,但它在段落中有更多的单词,因此不是解决方案: Ein toller Beispieltext ist Blindtext。 Er hat einpaarWörter。

我的想法是剪切所有不必要的字母,然后将空格上的文本块拆分成所有单词的数组。所以我可以得到单词的位置并计算在一个搜索单词的第一次出现和所有其他搜索单词的第一次出现之间有多少单词。这样我就需要通过整个数组并比较所有可能的段落长度,并采用最短的段落。

你认为这是最好的方法还是你能指出我如何解决这个问题?

2 个答案:

答案 0 :(得分:0)

Foreward

我认为这是一个两部分问题:

  1. 我首先会找到所有带有必填词
  2. 的句子
  3. 使用PHP word count function
  4. 计算生成的单词

    描述

    (?<=.\s|.\s\s|^)(?=[^.]*ein)(?=[^.]*Beispieltext)(?=[^.]*der)(?=[^.]*paar)(?=[^.]*Wörter)[^.]*.
    

    Regular expression visualization

    此表达式将执行以下操作:

    • 使用多个前瞻构造(?=[^.]DesiredWord)来确保每个所需的单词都存在
    • 找到包含所有所需单词的所有句子

    实施例

    现场演示

    https://regex101.com/r/lR7uK3/1

    示例文字

      

    Ein toller Beispieltext ist der Blindtext。 Er hat einpaarWörter。 Dies ist ein Beispieltext,der einpaarWörterhatund auch noch ein paar mehr,um die Zeileetwaslängerzumahen。 Darüberhinausist ernurdafürda,umgenügendTesttextzusammenzubekommen。 Dem Text selbst macht das nicht so viel aus。 Frühereinmalmehr,als er noch nicht so selbstbewusst war。 Heute kennt er seine Rolle als Blindtextundfügtsichselbstbewusst ein。 Er ist ja irgendwie wichtig。 Manchmal jedoch,ganz manchmal,weint er in der Nacht,weil er niemals bis zum Ende gelesen wird。 Doch das hat ja jetztzumGlückinEnde。

    样本匹配

      

    Dies ist ein Beispieltext,der einpaarWörterhatund auch noch ein paar mehr,um die Zeile etwaslängerzumahen。

    PHP字数

    $Sentence = "Dies ist ein Beispieltext, der ein paar Wörter hat und auch noch ein paar mehr, um die Zeile etwas länger zu machen.";
    
    echo str_word_count($Sentence);
    

    返回:22

答案 1 :(得分:0)

你描述的算法可能没问题,但是当涉及到&#34时,它没有明确规定......这样我就需要遍历整个数组&#34;

完成清理并拆分为单词后,为关键字创建地图会更容易,因此您可以快速了解文本中的单词是否匹配(使用isset())。然后你可以将文本数组缩小为匹配单词数组(使用array_filter()),仍然保留它们在原始单词数组中出现的位置的索引。

然后,算法将遍历该缩小的数组并跟踪这些单词的窗口(范围)。在右侧,只要并非所有必需的单词都在其中,窗口就会放大,当左侧单词已经出现在窗口的其他位置时,或者在找到候选解决方案之后,它会在左侧缩小。这样,您的窗口将遍历整个(缩小的)文本数组。您只会跟踪代表最短词组的窗口。所以最后你有最佳解决方案,只需要将窗口边界转换回原始文本数组中的短语。

不区分大小写匹配可以通过以小写(使用strtolower)存储事物,并使用原始的套接字符串(以数组格式)来生成输出来实现。

这是一个实现上述算法的函数:

function findFragment($text, $words) {
    // Remove non-A-Z letters
    $text = preg_replace("/[^a-z ]/i", "", $text);
    $words = preg_replace("/[^a-z ]/i", "", $words);
    // Create a map keyed by the words to find, with as value 
    // the number of occurrences in current sub-phrase
    $words_map = array_fill_keys(str_word_count(strtolower($words), 2), 0);
    // Put all words of text in an array
    $text_arr = str_word_count($text, 1);
    $text_low_arr = str_word_count(strtolower($text), 1);
    // Filter only matching words from the text, keeping their original indexes.
    $matches = array_filter($text_low_arr, function ($word) use ($words_map) {
        return isset($words_map[$word]);
    });
    // How many distinct words need to be matched to have a candidate phrase
    $matches_left = count($words_map);
    // Keep track of how long the shortest phrase is
    $min_words = count($text_arr) + 1; // start "infinite"
    // Loop over all matching words as the last word of a possible phrase
    foreach($matches as $i => $match) {
        $phrase[$i] = $match; // Add to the phrase
        $words_map[$match]++; // Increase count for this particular word
        if ($words_map[$match] > 1) continue; // Nothing new was added
        // Additional word found
        $matches_left--;
        if ($matches_left) continue; // Still need more words
        // Phrase has all words
        // Remove words from left which occur elsewhere in the phrase
        while ($words_map[reset($phrase)] > 1) {
            $words_map[reset($phrase)]--;
            unset($phrase[key($phrase)]);
        }
        // How many words are in this phrase?
        $num_words = $i - key($phrase) +1;
        if ($num_words < $min_words) {
            // It is shorter than we had so far
            $min_words = $num_words;
            $best_start = key($phrase);
        }
        // Remove first word from phrase before finding new candidate phrases
        $words_map[reset($phrase)]--;
        unset($phrase[key($phrase)]);
        $matches_left++;
    }
    // return best result
    return implode(" ", array_slice($text_arr, $best_start, $min_words));
}

你会这样称呼:

echo findFragment($text, $words);

对于您在问题中提供的样本数据,它会返回所需的答案:

  

Beispieltext der ein paar Wrter

看到它在eval.in上运行。