2017-11-12 4 views
3

下でIは、配列の値を持つ出力を比較するコードを持っており、唯一のアレイ内の単語と動作を終了:は、配列の値により、変数の値を交換するが、条件

最初のコード(単なる例

$myVar = 'essa pizza é muito gostosa, que prato de bom sabor'; 
$myWords=array(
    array('sabor','gosto','delicia'), 
    array('saborosa','gostosa','deliciosa'), 
); 

foreach($myWords as $words){ 
    shuffle($words); // randomize the subarray 
    // pipe-together the words and return just one match 
    if(preg_match('/\K\b(?:'.implode('|',$words).')\b/',$myVar,$out)){ 
     // generate "replace_pair" from matched word and a random remaining subarray word 
     // replace and preserve the new sentence 
     $myVar=strtr($myVar,[$out[0]=>current(array_diff($words,$out))]); 
    } 
} 
echo $myVar; 

私の質問:

// wrong output: $myVar = "minha irmã alanné é not aquela blnode, elere é a bom plperito"; 
$myVar = "my sister alannis is not that blonde, here is a good place"; 
$myWords=array(array("is","é"), 
    array("on","no"), 
    array("that","aquela"), 
    //array("blonde","loira"), 
    //array("not","não"), 
    array("sister","irmã"), 
    array("my","minha"), 
    //array("nothing","nada"), 
    array("myth","mito"), 
    array("he","ele"), 
    array("good","bom"), 
    array("ace","perito"), 
    // array("here","aqui"), //if [here] it does not exist, it is not to do replacement from the line he=ele = "elere" non-existent word 
); 
$replacements = array_combine(array_column($myWords,0),array_column($myWords,1)); 
$myVar = strtr($myVar,$replacements); 
echo $myVar; 
// expected output: minha irmã alannis é not aquela blonde, here é a bom place 
// avoid replace words slice! 

:私は常に値を交換するために、(私は常に1から列0を変更、私は置換の精度が欲しい、ランドをしたくない)ランド/シャッフルのためではない第二のコードを、持っています期待出力:minha IRMA alanniséaquela金髪ではない、ここでは、BOMの場所

// avoid replace words slice! always check if the word exists in the array before making the substitution. 

alanné、blnode、éelereつのワードは、書き込み存在単語ないこと

:、plperito

それは出力が配列myWordsに存在する実際の単語のであろうかどうかを調べ、これはのような入力ミス回避しますエラー。 2番目のコードではどうしますか?

要するに、交換は完全な単語/キー、既存の単語で行わなければなりません。キーワードのスライスを使用して奇妙な何かを作成しないでください!

答えて

1

私の以前の方法は非常に非効率でした。あなたが処理しているデータの量はわかりませんでしたが、私たちが4000行以上上がっていれば、効率は非常に重要です(以前の質問に基づいて、strtr()関連処理を考えて脳が詰まっていたと思います)。これは私の新しい/改善された解決策であり、以前の解決策をほこりの中に残すことを期待しています。

コード:(Demo

$myVar="My sister alannis Is not That blonde, here is a good place. I know Ariane is not MY SISTER!"; 
echo "$myVar\n"; 

$myWords=array(
    array("is","é"), 
    array("on","no"), 
    array("that","aquela"), 
    array("sister","irmã"), 
    array("my","minha"), 
    array("myth","mito"), 
    array("he","ele"), 
    array("good","bom"), 
    array("ace","perito"), 
    array("i","eu") // notice I must be lowercase 
); 
$translations=array_combine(array_column($myWords,0),array_column($myWords,1)); // or skip this step and just declare $myWords as key-value pairs 

// length sorting is not necessary 
// preg_quote() and \Q\E are not used because dealing with words only (no danger of misinterpretation by regex) 

$pattern='/\b(?>'.implode('|',array_keys($translations)).')\b/i'; // atomic group is slightly faster (no backtracking) 
/* echo $pattern; 
    makes: /\b(?>is|on|that|sister|my|myth|he|good|ace)\b/i 
    demo: https://regex101.com/r/DXTtDf/1 
*/ 
$translated=preg_replace_callback(
    $pattern, 
    function($m)use($translations){ // bring $translations (lookup) array to function 
     $encoding='UTF-8'; // default setting 
     $key=mb_strtolower($m[0],$encoding); // standardize keys' case for lookup accessibility 
     if(ctype_lower($m[0])){ // treat as all lower 
      return $translations[$m[0]]; 
     }elseif(mb_strlen($m[0],$encoding)>1 && ctype_upper($m[0])){ // treat as all uppercase 
      return mb_strtoupper($translations[$key],$encoding); 
     }else{ // treat as only first character uppercase 
      return mb_strtoupper(mb_substr($translations[$key],0,1,$encoding),$encoding) // uppercase first 
        .mb_substr($translations[$key],1,mb_strlen($translations[$key],$encoding)-1,$encoding); // append remaining lowercase 
     } 
    }, 
    $myVar); 

echo $translated; 

出力:

My sister alannis Is not That blonde, here is a good place. I know Ariane is not MY SISTER! 
Minha irmã alannis É not Aquela blonde, here é a bom place. Eu know Ariane é not MINHA IRMÃ! 

この方法:

  • $myVarを通じてのみパスのすべての部分配列のためではない1つのパスを行います$myWords
  • は、検索配列の並べ替え($myWords/$translations)を気にすることはありません。
  • という単語のみが翻訳されているため、正規表現のエスケープ(preg_quote())やパターンコンポーネントのリテラル(\Q..\E)を気にする必要はありません。
  • は、完全な単語一致のみが置き換えられるように単語境界を使用します。
  • は、バックトラッキングを拒否しながら精度を維持するマイクロ最適化として原子グループを使用します。
  • は、安定性/保守性/再利便性のために$encodingの値を宣言します。
  • 場合、無神経と一致しますが、大文字と小文字の区別に代わる...英語の一致がある場合:
    1. すべて小文字なので、交換
    2. はそう、すべて大文字(および単一の文字より大きい)であります交換
    3. は資産である(複数の文字列の最初の文字だけ)ので、交換は@mickmackusaこんにちは、私は私がしても、より完全な質問を申し訳ありませんでした
+0

ありがとうmickmackusa ...もう一度ありがとう:-) –

1

残念ながらstrtr()は「単語境界無知」なのでこの仕事の間違ったツールです。単語全体を対象にするには、単語境界で正規表現パターンを使用するより簡単な方法はありません。必要な場合にのみ、マルチバイト・バージョンを使用して、

また、長い文字列が一致短い文字列(他の文字列内に存在することができる文字列)の前にあることを確認するには、最短と最長/下降(文字列の長さによって$myWordsをソートする必要があります)。

単語の並びが並べ替えられて正規表現パターンに変換されると、patternとのパラメータがpreg_replace()になります。

コード(Demo

$myVar = "my sister alannis is not that blonde, here is a good place"; 
$myWords=array(
    array("is","é"), 
    array("on","no"), 
    array("that","aquela"), 
    array("sister","irmã"), 
    array("my","minha"), 
    array("myth","mito"), 
    array("he","ele"), 
    array("good","bom"), 
    array("ace","perito") 
); 
usort($myWords,function($a,$b){return mb_strlen($b[0])<=>mb_strlen($a[0]);}); // sort subarrays by first column multibyte length 
// remove mb_ if first column holds no multi-byte characters. strlen() is much faster. 

foreach($myWords as &$words){ 
    $words[0]='/\b'.$words[0].'\b/i'; // generate patterns using search word, word boundaries, and case-insensitivity 
} 

//var_export($myWords); 
//var_export(array_column($myWords,0)); 
//var_export(array_column($myWords,1)); 

$myVar=preg_replace(array_column($myWords,0),array_column($myWords,1),$myVar); 
echo $myVar; 

出力:

minha irmã alannis é not aquela blonde, here é a bom place 

これは行いません何がマッチした部分文字列の場合に感謝です。つまり、myMyの両方がminhaに置き換えられます。

異なる筐体に対応するには、preg_replace_callback()を使用する必要があります。 - 交換後に保存オリジナルケースを見て、これを実行します(Demo)<

コード:ここで

は、(大文字の最初の文字の単語ではなく、すべて大文字の単語を扱う)という配慮です。

foreach($myWords as $words){ 
    $myVar=preg_replace_callback(
     $words[0], 
     function($m)use($words){ 
      return ctype_upper(mb_substr($m[0],0,1))? 
       mb_strtoupper(mb_substr($words[1],0,1)).mb_strtolower(mb_substr($words[1],1)): 
       $words[1]; 
     }, 
     $myVar); 
} 
echo $myVar; 
+0

ですそれをもっと明確にするために以前のケースを使用しましたが、私はそれを捕まえたことがあります。あなたがもう一度私を助けることができるなら、更新を見てください。お願いします。 –

+0

本当にありがとう、それは私をたくさん助けました、それは再び多くの助け、それはすべての可能なテストで完璧に動作しました!ありがとう! :-D –

+1

こんにちは@mickmackusa、あなたのアプローチでありがとう!遅れて申し訳ありませんが、私はこれらすべての時間中にPCを離れました!はい、それは本当にあなたの部分についての良い洞察力でした、私は常に大文字と小文字の問題があるかもしれないことを知っているので、変数にstrtolowerを使用する前に、それらに格納された文字列で何かを行う!必要ならucfirst、そして必要ならそれは敷物の下から汚れを隠すための方法です。あなたの上のアイデアはより良いコードになります。そして、2番目のコードは私にここの別の状況でそれを適用するアイデアを与えました。ありがとうございました.-) –

関連する問題