2017-02-20 50 views
0

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

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

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

+1

正则表达式不能自己做到这一点。你必须找到所有匹配的正则表达式,然后按照长度排序并显示第一个。 – Barmar

+0

您可能需要一些代码,例如您正在搜索的内容和方式。 – AbraCadaver

回答

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

我认为你可以使用正则表达式实现这一目标的唯一途径,就是在希望的顺序词第一,排序在你的情况下,从短到长。

然后,如果您的单词数量相对较少,为了表现,可以将单词连接起来并同时检查第一个匹配项。这是可能的,因为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; 
} 

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

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]; 
+0

@woo感谢您的回答。这对我帮助很大 。干杯! –