RegExp PHP显示最小的匹配

时间:2017-02-20 19:42:45

标签: php regex algorithm

我想在php中获得正则表达式的最小匹配。

例如:如果我有电视和电话这两个词并且用户输入是tel,我的正则表达式应该返回最小的单词,在这种情况下是电话。 简而言之,我试图像搜索脚本一样。但是对于用户输入中缺少的字母,我使用此t[a-zA-Z0-9]{0,2}l[a-zA-Z0-9]{0,},因此我的最后一个字母将跟随N个字符。

我的问题是:如何进行REGEXP显示最小的单词。

3 个答案:

答案 0 :(得分:1)

很遗憾,你无法做到。正则表达式可以匹配您想要的,但它不提供任何比较子匹配的功能。您必须匹配整个字符串,并根据您的情况通过PHP代码比较子匹配。

// your array of matched words
$words = array(...);

$foundWordLength = null;
$foundWord = '';

foreach ($words as $word) {
   if (strlen($word) < $foundWordLength || $foundWordLength === null) {
      $wordLength = strlen($word);
      $foundWord = $word;
   }
}

echo $foundWord;

答案 1 :(得分:1)

我认为你能用正则表达式实现它的唯一方法是首先按照理想的顺序对单词进行排序,在你的情况下从最短到最长。

然后,如果你有相对少量的单词,为了表现,可以连接单词并同时检查第一个匹配。这是可能的,因为PHP RegExp实现从左到右执行搜索。请参阅下面示例中的函数search_short()

无论如何,循环和检查从最低点开始的单词也会起作用。检查下面示例中的函数search_long()

<?php
$given = [
    'telephone',
    'television',
];
// NB: Do not forget to sanitize user input, i.e. $query
echo (search_short($given, 'tele') ?: 'Nothing found') . PHP_EOL;
echo (search_long($given, 'tele') ?: 'Nothing found') . PHP_EOL;
echo (search_short($given, 't[a-zA-Z0-9]{0,2}l[a-zA-Z0-9]{0,}') ?: 'Nothing found') . PHP_EOL;
echo (search_long($given, 't[a-zA-Z0-9]{0,2}l[a-zA-Z0-9]{0,}') ?: 'Nothing found') . PHP_EOL;

/**
 * @param string[] $given
 * @param string   $query
 *
 * @return null|string
 */
function search_short($given, $query)
{

    // precalculating the length of each word, removing duplicates, sorting
    $given = array_map(function ($word) {
        return mb_strlen($word); // `mb_strlen()` is O(N) function, while `strlen()` is O(1)
    }, array_combine($given, $given));
    asort($given);

    // preparing the index string
    $index = implode(PHP_EOL, array_keys($given));
    // and, finally, searching (the multiline flag is set)
    preg_match(
        sprintf('/^(?<word>%s\w*)$/mu', $query), // injecting the query word
        $index,
        $matches
    );

    // the final pattern looks like: "/^(?P<word>tele\w*)$/mui"
    if (array_key_exists('word', $matches)) {
        return $matches['word'];
    }
    return null;
}

/**
 * @param string[] $given
 * @param string   $query
 *
 * @return null|string
 */
function search_long($given, $query)
{
    $pattern = sprintf('/^(?<word>%s\w*)$/u', $query);

    // precalculating the length of each word, removing duplicates, sorting
    $given = array_map(function ($word) {
        return mb_strlen($word);
    }, array_combine($given, $given));
    asort($given);


    foreach ($given as $word => $count) {
        if (preg_match($pattern, $word, $matches)) {
            if (array_key_exists('word', $matches)) {
                return $matches['word'];
            }
        }
    }
    return false;
}

当然,它不是最有效的算法,可能会以多种方式进行改进。但是要完成有关所需范围和用途的更多信息。

答案 2 :(得分:1)

正则表达式引擎通常既没有预期的内存来存储复杂的条件,也没有编程语言功能的好处来提供复杂的比较。

如果标记没有漫无目的地完成,您可以使用更多行来完成工作。

$str = 'television and telephone';
preg_match_all('/tel\w*/', $str, $matches);
usort($matches[0], function($a, $b) {
    return strlen($a) <=> strlen($b);
});
echo $matches[0][0];