2017-02-20 11 views
0

私はPHPで正規表現の最小一致を取得しようとしています。RegExp PHP最小の一致を表示

例:テレビと電話という言葉があり、ユーザー入力がtelの場合、正規表現は最小の単語(この場合は電話)を返します。 要するに、私は検索スクリプトのようにしようとしています。しかし、ユーザーの入力に欠けている文字については、私はこの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あなたの答えに感謝します。それは私をたくさん助けました。乾杯! –

関連する問題