обмен значениями переменной, по значениям массива, но при условии

У меня есть код, который сравнивает вывод со значениями массива, и завершает операцию только со словами в массиве:

Первый код (просто пример)

$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;

Мой вопрос:

У меня есть второй код, который не предназначен для rand / shuffle (я не хочу rand, я хочу точности в подстановках, я всегда изменяю столбцы с 0 по 1), чтобы всегда обмениваться значениями:

// 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!

ожидаемый выход: minha irmã alannis — не блондиночка

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

alanné, blnode, elere, plperito

он проверяет, будут ли выходные данные состоять из реальных слов, которые существуют в массиве myWords, это позволяет избежать ошибок ввода, таких как:

что 4 слова не существуют слова, ошибка записи. как ты делаешь это для второго кода?

   короче говоря, обмен должен быть сделан полным словом / ключом, существующим словом. а не создавать что-то странное, используя кусочки ключевых слов!

3

Решение

Мой предыдущий метод был невероятно неэффективным. Я не понимал, сколько данных вы обрабатываете, но если у нас более 4000 строк, то эффективность жизненно важна (думаю, мой мозг застрял, думая о strtr() связанная обработка на основе вашего предыдущего вопроса (ов)). Это мое новое / улучшенное решение, которое, как я ожидаю, оставит мое предыдущее решение в пыли.

Код: (демонстрация)

$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Ã!

Этот метод:

  • делает только 1 пройти через $myVar, не 1 проход для каждого подмассива $myWords,
  • не заморачивается с сортировкой поискового массива ($myWords/$translations).
  • не заморачивается с выходом регулярного выражения (preg_quote()) или сделать компоненты шаблона буквальными (\Q..\E) потому что только слова переводятся.
  • использует границы слов, так что заменяются только полные совпадения слов.
  • использует атомную группу в качестве микрооптимизации, которая поддерживает точность, не допуская возврата.
  • объявляет $encoding значение для стабильности / ремонтопригодности / повторного использования.
  • соответствует регистронезависимости, но заменяется регистрозависимостью … если английское совпадение:
    1. Все строчные, поэтому идет замена
    2. Все в верхнем регистре (и больше, чем один символ), поэтому замена
    3. С заглавной буквы (только первый символ многосимвольной строки), поэтому замена
1

Другие решения

к несчастью strtr() это неправильный инструмент для этой работы, потому что он «невежественен». Для целевых слов нет более простого способа, чем использовать шаблон регулярных выражений с границами слов.

Кроме того, чтобы убедиться, что более длинные строки совпадают до более коротких строк (строк, которые могут существовать внутри других строк), вы должны отсортировать $myWords по длине строки (по убыванию / от самой длинной до самой короткой; использование многобайтовой версии только при необходимости).

После того, как массив слов отсортирован и преобразован в отдельные шаблоны регулярных выражений, вы можете подавать массивы в pattern а также replace параметры preg_replace(),

Код (демонстрация)

$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

То, что это не делает, ценит случай соответствующих подстрок. Я имею в виду, my а также My оба будут заменены minha,

Для размещения разных корпусов вам нужно будет использовать preg_replace_callback(),

Вот это соображение (которое обрабатывает заглавные слова из первых букв, а не ВСЕ слова из CAPS):

Код (демонстрация) <- запустите это, чтобы увидеть, что оригинальный корпус сохранился после замены.

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;
1

По вопросам рекламы [email protected]