У меня есть символы массива, которые я хочу заменить, но мне нужно сгенерировать все возможности
$lt = array(
'a' => 'ą',
'e' => 'ę',
'i' => 'į',
);
Например, если у меня есть эта строка:
tazeki
Там может быть огромное количество результатов:
tązeki
tazęki
tązęki
tazekį
tązekį
tazękį
tązękį
У меня вопрос, какую формулу использовать для всех вариантов?
Это должно работать для вас, легко и просто:
Что делает этот код?
1. Часть данных
В части данных я просто определяю строку и замену для одного символа с ассоциативным массивом (поиск символа в качестве ключа, замена в качестве значения).
2. getReplacements()
функция
Эта функция получает все комбинации символов, которые должны быть заменены в этом формате:
key = index in the string
value = character
Таким образом, в этом примере кода массив будет выглядеть примерно так:
Array (
[0] => Array (
[1] => a
)
[1] => Array (
[3] => e
)
[2] => Array (
[3] => e
[1] => a
)
[3] => Array (
[5] => i
)
[4] => Array (
[5] => i
[1] => a
)
[5] => Array (
[5] => i
[3] => e
)
[6] => Array (
[5] => i
[3] => e
[1] => a
)
)
Как видите, этот массив содержит все комбинации символов, которые должны быть заменены, в следующем формате:
[0] => Array (
//^^^^^ The entire sub array is the combination which holds the single characters which will be replaced
[1] => a
//^ ^ A single character of the full combination which will be replaced
//| The index of the character in the string (This is that it also works if you have a character multiple times in your string)
// e.g. 1 -> t *a* z e k i
// ^ ^ ^ ^ ^ ^
// | | | | | |
// 0 *1* 2 3 4 5
)
Так как же получить все комбинации?
Довольно просто я зацикливаюсь на каждом отдельном символе, который я хочу заменить на цикл foreach, а затем перебираю каждую отдельную комбинацию и объединяю ее с символом, который в настоящее время является значением цикла foreach.
Но чтобы заставить это работать, вы должны начать с пустого массива. Итак, в качестве простого примера, чтобы увидеть и понять, что я имею в виду:
Characters which have to be replaced (Empty array is '[]'): [1, 2, 3]
//new combinations for the next iteration
|
Character loop for NAN*:
Combinations:
- [] | -> []
Character loop for 1:
Combinations:
- [] + 1 | -> [1]
Character loop for 2:
Combinations:
- [] + 2 | -> [2]
- [1] + 2 | -> [1,2]
Character loop for 3:
Combinations:
- [] + 3 | -> [3]
- [1] + 3 | -> [1,3]
- [2] + 3 | -> [2,3]
- [1,2] + 3 | -> [1,2,3]
//^ All combinations here
* NAN: не номер
Итак, как вы можете видеть, всегда есть: (2^n)-1
Всего комбинаций. Также от этого метода остается пустой массив в массиве комбинаций, поэтому, прежде чем я верну массив, я просто использую array_filter()
удалить все пустые массивы и array_values()
переиндексировать весь массив.
3. Запасная часть
Таким образом, чтобы получить все символы из строки, из которой будут строиться комбинации, я использую эту строку:
array_intersect(str_split($str), array_keys($replace))
Это просто совпадение с array_intersect()
из строки в виде массива с str_split()
и ключи из массива замены с array_keys()
.
В этом коде массив, который вы передаете getReplacements()
функция будет выглядеть примерно так:
Array
(
[1] => a
//^ ^ The single character which is in the string and also in the replace array
//| Index in the string from the character
[3] => e
[5] => i
)
4. Заменить все комбинации
В конце вам нужно только заменить все комбинации в исходной строке на массив замены. Для этого я перебираю все комбинации и заменяю каждый отдельный символ в строке на соответствующий символ из массива замены.
Это можно просто сделать с помощью этой строки:
$tmp = substr_replace($tmp, $replace[$v], $k, 1);
//^^^^^^^^^^^^^^ ^^^^^^^^^^^^ ^^ ^ Length of the replacement
//| | | Index from the string, where it should replace
//| | Get the replaced character to replace it
//| Replaces every single character one by one in the string
Для получения дополнительной информации о substr_replace()
см. руководство: http://php.net/manual/en/function.substr-replace.php
После этой строки вы просто добавляете замененную строку в массив результатов и снова помещаете строку в исходную строку.
Код:
<?php
//data
$str = "tazeki";
$replace = array(
'a' => 'ą',
'e' => 'ę',
'i' => 'į',
);function getReplacements($array) {
//initalize array
$results = [[]];
//get all combinations
foreach ($array as $k => $element) {
foreach ($results as $combination)
$results[] = [$k => $element] + $combination;
}
//return filtered array
return array_values(array_filter($results));
}
//get all combinations to replace
$combinations = getReplacements(array_intersect(str_split($str), array_keys($replace)));
//replace all combinations
foreach($combinations as $word) {
$tmp = $str;
foreach($word as $k => $v)
$tmp = substr_replace($tmp, $replace[$v], $k, 1);
$result[] = $tmp;
}
//print data
print_r($result);
?>
Выход:
Array
(
[0] => tązeki
[1] => tazęki
[2] => tązęki
[3] => tazekį
[4] => tązekį
[5] => tazękį
[6] => tązękį
)
Вот решение специально для вашей задачи. Вы можете передать любое слово и любой массив для замены, это должно работать.
<?php
function getCombinations($word, $charsReplace)
{
$charsToSplit = array_keys($charsReplace);
$pattern = '/('.implode('|', $charsToSplit).')/';
// split whole word into parts by replacing symbols
$parts = preg_split($pattern, $word, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$replaceParts = array();
$placeholder = '';
// create string with placeholders (%s) for sptrinf and array of replacing symbols
foreach ($parts as $wordPart) {
if (isset($charsReplace[$wordPart])) {
$replaceParts[] = $wordPart;
$placeholder .= '%s';
} else {
$placeholder .= $wordPart;
}
}
$paramsCnt = count($replaceParts);
$combinations = array();
$combinationsCnt = pow(2, $paramsCnt);
// iterate all combinations (with help of binary codes)
for ($i = 0; $i < $combinationsCnt; $i++) {
$mask = sprintf('%0'.$paramsCnt.'b', $i);
$sprintfParams = array($placeholder);
foreach ($replaceParts as $index => $char) {
$sprintfParams[] = $mask[$index] == 1 ? $charsReplace[$char] : $char;
}
// fill current combination into placeholder and collect it in array
$combinations[] = call_user_func_array('sprintf', $sprintfParams);
}
return $combinations;
}$lt = array(
'a' => 'ą',
'e' => 'ę',
'i' => 'į',
);
$word = 'stazeki';
$combinations = getCombinations($word, $lt);
print_r($combinations);
// Оutput:
// Array
// (
// [0] => stazeki
// [1] => stazekį
// [2] => stazęki
// [3] => stazękį
// [4] => stązeki
// [5] => stązekį
// [6] => stązęki
// [7] => stązękį
// )
Это реализация в PHP:
<?php
/**
* String variant generator
*/
class stringVariantGenerator
{
/**
* Contains assoc of char => array of all its variations
* @var array
*/
protected $_mapping = array();
/**
* Class constructor
*
* @param array $mapping Assoc array of char => array of all its variation
*/
public function __construct(array $mapping = array())
{
$this->_mapping = $mapping;
}
/**
* Generate all variations
*
* @param string $string String to generate variations from
*
* @return array Assoc containing variations
*/
public function generate($string)
{
return array_unique($this->parseString($string));
}
/**
* Parse a string and returns variations
*
* @param string $string String to parse
* @param int $position Current position analyzed in the string
* @param array $result Assoc containing all variations
*
* @return array Assoc containing variations
*/
protected function parseString($string, $position = 0, array &$result = array())
{
if ($position <= strlen($string) - 1)
{
if (isset($this->_mapping[$string{$position}]))
{
foreach ($this->_mapping[$string{$position}] as $translatedChar)
{
$string{$position} = $translatedChar;
$this->parseString($string, $position + 1, $result);
}
}
else
{
$this->parseString($string, $position + 1, $result);
}
}
else
{
$result[] = $string;
}
return $result;
}
}
// This is where you define what are the possible variations for each char
$mapping = array(
'e' => array('#', '_'),
'p' => array('*'),
);
$word = 'Apple love!';
$generator = new stringVariantGenerator($mapping);
print_r($generator->generate($word));
Это вернуло бы:
Array
(
[0] => A**l# lov#!
[1] => A**l# lov_!
[2] => A**l_ lov#!
[3] => A**l_ lov_!
)
В вашем случае, если вы хотите использовать само письмо в качестве допустимого переведенного значения, просто добавьте его в массив.
$lt = array(
'a' => array('a', 'ą'),
'e' => array('e', 'ę'),
'i' => array('i', 'į'),
);
Я не уверен, что вы можете сделать это с ключами и значением, но как два массива определенно.
$find = array('ą','ę','į');
$replace = array('a', 'e', 'i');
$string = 'tązekį';
echo str_replace($find, $replace, $string);
Я не уверен, что понимаю ваш вопрос, но вот мой ответ 🙂
$word = 'taxeki';
$word_arr = array();
$word_arr[] = $word;
//Loop through the $lt-array where $key represents what char to search for
//$letter what to replace with
//
foreach($lt as $key=>$letter) {
//Loop through each char in the $word-string
for( $i = 0; $i <= strlen($word)-1; $i++ ) {
$char = substr( $word, $i, 1 );
//If current letter in word is same as $key from $lt-array
//then add a word the $word_arr where letter is replace with
//$letter from the $lt-array
if ($char === $key) {
$word_arr[] = str_replace($char, $letter, $word);
}
}
}
var_dump($word_arr);
Я предполагаю, что у вас есть известное количество элементов в вашем массиве, и я предполагаю, что это число равно 3. У вас будут дополнительные циклы, если у вас есть дополнительные элементы в вашем массиве $ lt.
$lt = array(
'a' => array('a', 'x'),
'e' => array('e', 'x'),
'i' => array('i', 'x')
);
$str = 'tazeki';
foreach ($lt['a'] as $a)
foreach ($lt['e'] as $b)
foreach ($lt['i'] as $c) {
$newstr = str_replace(array_keys($lt), array($a, $b, $c), $str);
echo "$newstr<br />\n";
}
Если количество элементов в $lt
неизвестно или переменная, то это не хорошее решение.
Что ж, хотя @ Rizier123 и другие уже предоставили хорошие ответы, дадут четкие объяснения, я также хотел бы оставить свой вклад. На этот раз, почитая Путь короткого исходного кода над читабельностью … 😉
$lt = array('a' => 'ą', 'e' => 'ę', 'i' => 'į');
$word = 'tazeki';
for ($i = 0; $i < strlen($word); $i++)
$lt[$word[$i]] && $r[pow(2, $u++)] = [$lt[$word[$i]], $i];
for ($i = 1; $i < pow(2, count($r)); $i++) {
for ($w = $word, $u = end(array_keys($r)); $u > 0; $u >>= 1)
($i & $u) && $w = substr_replace($w, $r[$u][0], $r[$u][1], 1);
$res[] = $w;
}
print_r($res);
Выход:
Array
(
[0] => tązeki
[1] => tazęki
[2] => tązęki
[3] => tazekį
[4] => tązekį
[5] => tazękį
[6] => tązękį
)