我认为您可以使用正则表达式实现它的唯一方法是首先按理想的顺序对单词进行排序,在您的情况下从最短到最长。
然后,如果您的单词数量相对较少,为了性能起见,可以将单词连接起来并同时检查第一个匹配项。这是可能的,因为 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;
}
当然,它不是最有效的算法,可以通过多种方式进行改进。但是为了完成这个需要更多关于范围和使用的信息。