I want to implement a simple Arabic to English transliteration. I have defined a mapping array like the following:
$mapping = array('ﺏ' => 'b', 'ﺕ' => 't', ...)
I expect the following code to convert an Arabic string to its corresponding transliteration
$str = "رضي الدين";
$strlen = mb_strlen( $str, "UTF-8" );
for( $i = 0; $i <= $strlen; $i++ ) {
$char = mb_substr( $str, $i, 1, "UTF-8" );
echo bin2hex($char); // 'd8b1' for ﺭ
// echo $mapping["$char"];
}
But $char does not match the keys. How can this be solved?
The source code is loaded in UTF-8.
EDIT
When I do bin2hex() on each key of $mapping I get values different than that I get with corresponding $char. For example, for ﺭ I get efbaad and d8b1. They obviously don't match and they are not converted.
foreach ($mapping as $k => $v) {
echo $k . ' ' . bin2hex($k) . '<br>'; // 'efbaad' for ﺭ
}
Only 'ي' gets same values and is converted.
I do not know what's the problem!
EDIT2
This chart actually shows that both of these codes refer to ﺭ
I suggest you to use preg engine since it natively works well with UTF-8. mb_* is not a bad choice, of cause, but I think it's just more complicated.
I've made a sample for your case:
$sData = "رضي الدين";
$rgReplace = [
'ﺏ' => 'b',
'ﺕ' => 't',
'ن' => 'n',
'ي' => 'i',
'د' => 'f',
'ل' => 'l',
'ا' => 'a',
'ر' => 'r',
'ي' => 'i',
'ض' => 'g',
' ' => ' '
];
$sResult = preg_replace_callback('/./u', function($sChar) use ($rgReplace)
{
return $rgReplace[$sChar[0]];
}, $sData);
echo $sResult; //rgi alfin
as for your code - try to pass encoding directly (second parameter in mb_* functions)
The problem is that you didn't specify the encoding to both mb_strlen() and mb_substr(); the following works okay:
$str = "رضي الدين";
$mapping = array('ﺏ' => 'b', 'ﺕ' => 't', 'ر' => c);
$strlen = mb_strlen( $str, "UTF-8" );
for( $i = 0; $i <= $strlen; $i++ ) {
$char = mb_substr( $str, $i, 1 , "UTF-8");
echo $mapping["$char"];
}
Related
I have this string:
$string = 'Hello IV WorldX';
And I want to replace all roman numerals to integers.
I have the following function to convert roman to integer:
function roman2number($roman){
$conv = array(
array("letter" => 'I', "number" => 1),
array("letter" => 'V', "number" => 5),
array("letter" => 'X', "number" => 10),
array("letter" => 'L', "number" => 50),
array("letter" => 'C', "number" => 100),
array("letter" => 'D', "number" => 500),
array("letter" => 'M', "number" => 1000),
array("letter" => 0, "number" => 0)
);
$arabic = 0;
$state = 0;
$sidx = 0;
$len = strlen($roman);
while ($len >= 0) {
$i = 0;
$sidx = $len;
while ($conv[$i]['number'] > 0) {
if (strtoupper(#$roman[$sidx]) == $conv[$i]['letter']) {
if ($state > $conv[$i]['number']) {
$arabic -= $conv[$i]['number'];
} else {
$arabic += $conv[$i]['number'];
$state = $conv[$i]['number'];
}
}
$i++;
}
$len--;
}
return($arabic);
}
echo roman2number('IV');
Works great (try it on ideone). How do I search & replace through the string to replace all instances of roman numerals. Something like:
$string = romans_to_numbers_in_string($string);
Sounds like regex needs to come to the rescue... or?
Here's a simple regex to match roman numerals:
\b[0IVXLCDM]+\b
So, you can implement romans_to_numbers_in_string like this:
function romans_to_numbers_in_string($string) {
return preg_replace_callback('/\b[0IVXLCDM]+\b/', function($m) {
return roman2number($m[0]);
},$string);
}
There are some problems with this regex. Like, if you have a string like this:
I like roman numerals
It will become:
1 like roman numerals
Depending on your requirements, you can let it be, or you can modify the regex so that it doesn't convert single I's to numbers.
$array = [
'H',
'E',
'L',
'L',
'O',
];
This is my array. I want to print this array like this :
H
HE
HEL
HELL
HELLO
I want to do this dynamically .
For example, write a function to receive the array and do this with the array. Any array is possible.
You can use nested for loops to print the pattern as follows:
$array = [
'H',
'E',
'L',
'L',
'O',
];
echo printPattern($array);
function printPattern($array){
$ret = '';
for($i = 0; $i < count($array); $i++){
$str = '';
for($j = 0; $j < $i+1; $j++){
$str .= $array[$j];
}
$ret .= $str.'<br>';
}
return $ret;
}
Convert the array to a string, then iterate over the length of the string (either count the array or use strlen(), they'll be the same) and use substr() to get the given length, which will be the same as the number of the iteration.
$array = [
'H',
'E',
'L',
'L',
'O',
];
$string = implode("", $array);
for ($i = 0; $i <= count($array); $i++) {
echo substr($string, 0, $i)."\n";
}
Live demo at https://3v4l.org/ibXpK
I am trying to figure out how I can start looping through an array at a different index but when it reaches the end it loops back to the beginning and finishes the array. Basically, I need to be able to dynamically change the offset of the array.
What I am trying to do it associate a letter of the alphabet with a different alphabet letter to mix things up for a string.
Let's say I have a random array like so
$arr = array('a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k');
Then I have a string like so
$string = 'abcde';
And let's say I need to start at index in the array at 2 which would be 'c' => 'j' then finish the array to the end and then loop back to the beginning until it is finished.
What I want to do is replace each letter with the corresponding letter associated with it in the array. So the final string after it is replaced would look like
I would reconstruct the array with
$build = strtr($string,$arr);
which would echo gwjyk
But I need to start at a random point in the array and then finish it and go back to the beggining and finish the entire array.
So maybe I have an offset of 2.
$offset = 2;
As I mentioned in the comments, I would approach this using array_slice and then merging the two arrays in order to simply get a new array, then loop through it from start to finish.
Here's a fully functional solution (and a runnable version)- although I'd like to point out that the offset really doesn't change the results at all:
/**
* Goes through a string and replaces letters based on an array "map".
*
* #param string - $string
* #param int - $offset
*
* #return string
*/
function change_letters( $string, $offset ) {
$letters = ['a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k'];
// some defensive code to prevent notices or errors
if ( (int)$offset > count($letters)) {
echo '<p>Error: Offset is larger than the array of letters!</p>';
return $string;
}
// build new array based on passed-in offset
$new_array = array_slice($letters, $offset) + array_slice($letters, 0, $offset);
// at this point, array is ['c' => 'j', 'd' => 'y', 'e' => 'k', 'a' => 'g', 'b' => 'w']
// loop through the letters to replace...
foreach($new_array AS $from => $to) {
// swaps all instances of the "from" letter to the "to" letter in the string.
// NOTE: this could be easily modified to only replace n instances of the "from" letter
// like so: $string = str_ireplace( $from, $to, $string, 1); - would only replace 1 instance
$string = str_ireplace( $from, $to, $string );
}
return $string;
}
// Sample usage:
$word = 'abcde';
$new_word = change_letters( $word, 2); // "gwjk"
var_dump(2, $new_word);
$new_word = change_letters( $word, 5); // "gwjk"
var_dump(5, $new_word);
$new_word = change_letters( $word, 6); // "abcde"
var_dump(5, $new_word);
You can try:
<?php
$arr = array(1 => 2, 3 => 4, 5 => 6, 7 => 8, 9 => 0);
$STARTING_KEY = 3;
$array_keys = array_keys($arr);
$starting_index = array_search($STARTING_KEY, $array_keys);
for ($i = $starting_index; $i < sizeof($arr); $i++) {
echo $arr[$array_keys[$i]] . "\n";
}
for ($i = 0; $i < $starting_index; $i++) {
echo $arr[$array_keys[$i]] . "\n";
}
This will test all possible offsets for the string
$arr = array('a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k');
$str = "abcde";
$strlen = strlen($str);
$keys = array_keys($arr);
for ($j = 0; $j < $strlen; $j++)
{
$startIndex = $j;
echo "offset: " . $startIndex . ": ";
for ($i = $startIndex; $i < $strlen; $i++ )
{
$char = substr( $str, $i, 1 );
echo $arr[$char];
}
for ($i = 0; $i < $startIndex; $i++ )
{
$char = substr( $str, $i, 1 );
echo $arr[$char];
}
echo "\n";
}
Output:
offset: 0: gwjyk
offset: 1: wjykg
offset: 2: jykgw
offset: 3: ykgwj
offset: 4: kgwjy
As mentioned in the comment, another option for your example data could be using array_slice and setting the offset and the length parameters and use array_merge:
$arr = array('a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k');
$top = array_slice($arr, 0, 2);
$rest = array_slice($arr, 2);
print_r(array_merge($rest, $top));
Array
(
[c] => j
[d] => y
[e] => k
[a] => g
[b] => w
)
All that array slicin’n’dicing or using two loops to loop from x to end first, and start up to x second, is fine … but they don’t make for the most readable code IMHO.
Such an “offsetted circling-through” can be achieved in a quite trivial way with a numerically indexed array - a simple for loop, and the index “clamped down” by using modulo with the total number of array elements.
So in a case like this, I would perhaps prefer the following approach:
$arr = array('a' => 'g', 'b' => 'w', 'c' => 'j', 'd' => 'y', 'e' => 'k');
$c = count($arr);
$search = array_keys($arr);
$replace = array_values($arr);
$offset = 2; // zero-based
for( $i = 0; $i < $c; ++$i ) {
$idx = ( $i + $offset ) % $c;
echo $search[$idx] . ' => ' . $replace[$idx] . "<br>\n";
}
// result:
// c => j
// d => y
// e => k
// a => g
// b => w
I have this string:
$string = 'Hello IV WorldX';
And I want to replace all roman numerals to integers.
I have the following function to convert roman to integer:
function roman2number($roman){
$conv = array(
array("letter" => 'I', "number" => 1),
array("letter" => 'V', "number" => 5),
array("letter" => 'X', "number" => 10),
array("letter" => 'L', "number" => 50),
array("letter" => 'C', "number" => 100),
array("letter" => 'D', "number" => 500),
array("letter" => 'M', "number" => 1000),
array("letter" => 0, "number" => 0)
);
$arabic = 0;
$state = 0;
$sidx = 0;
$len = strlen($roman);
while ($len >= 0) {
$i = 0;
$sidx = $len;
while ($conv[$i]['number'] > 0) {
if (strtoupper(#$roman[$sidx]) == $conv[$i]['letter']) {
if ($state > $conv[$i]['number']) {
$arabic -= $conv[$i]['number'];
} else {
$arabic += $conv[$i]['number'];
$state = $conv[$i]['number'];
}
}
$i++;
}
$len--;
}
return($arabic);
}
echo roman2number('IV');
Works great (try it on ideone). How do I search & replace through the string to replace all instances of roman numerals. Something like:
$string = romans_to_numbers_in_string($string);
Sounds like regex needs to come to the rescue... or?
Here's a simple regex to match roman numerals:
\b[0IVXLCDM]+\b
So, you can implement romans_to_numbers_in_string like this:
function romans_to_numbers_in_string($string) {
return preg_replace_callback('/\b[0IVXLCDM]+\b/', function($m) {
return roman2number($m[0]);
},$string);
}
There are some problems with this regex. Like, if you have a string like this:
I like roman numerals
It will become:
1 like roman numerals
Depending on your requirements, you can let it be, or you can modify the regex so that it doesn't convert single I's to numbers.
I have array which have in letter format key.
'A' => array('WORD1','WORD2','WORD3'),
'B' => array('WORD1','WORD2','WORD3'),
'C' => array('WORD1','WORD2','WORD3'),
'D' => array('WORD1','WORD2','WORD3'),
'E' => array('WORD1','WORD2','WORD3'),
'F' => array('WORD1','WORD2','WORD3'),
'H' => array('WORD1','WORD2','WORD3'),
'G' => array('WORD1','WORD2','WORD3'),
...
I need to pick random value from each element. Example, when I set $output = "FGH"
Output will be:
F - (RANDOM WORD FROM ARRAY KEY F)\n
G - (RANDOM WORD FROM ARRAY KEY F)\n
H - (RANDOM WORD FROM ARRAY KEY H)\n
I used my code below but doesn't work..
$result = array();
foreach($chars as $char){
$random_key = array_rand($words[$char]); // get random key
$key = $words[$char][$random_key]; // get the word
unset($words[$char][$random_key]); // unset it so that it will never be repeated
$result[$key] = $char; // push it inside
}
Thanks to anyone that would help me
This gives a random word from whichever keys are specified in $output (note I have modified your $chars array slightly to make it obvious which value is being returned):
$chars = array(
'A' => array('A_WORD1','A_WORD2','A_WORD3'),
'B' => array('B_WORD1','B_WORD2','B_WORD3'),
'C' => array('C_WORD1','C_WORD2','C_WORD3'),
'D' => array('D_WORD1','D_WORD2','D_WORD3'),
'E' => array('E_WORD1','E_WORD2','E_WORD3'),
'F' => array('F_WORD1','F_WORD2','F_WORD3'),
'G' => array('G_WORD1','G_WORD2','G_WORD3'),
'H' => array('H_WORD1','H_WORD2','H_WORD3')
);
$output = 'FGH';
$result = array();
foreach(str_split($output) as $key) {
$result[] = $chars[$key][array_rand($chars[$key])];
}
var_dump($result);
The secret sauce here is the str_split() function.
<?php
$a=array("red","green","blue","yellow","brown");
$random_keys=array_rand($a,3);
echo $a[$random_keys[0]]."<br>";
echo $a[$random_keys[1]]."<br>";
echo $a[$random_keys[2]];
?>
for your reference : http://php.net/manual/en/function.array-rand.php
If you have already set up the random arrays to pick words from, it's quite straight forward with count() and rand().
//$globalWordArray = .......;
$selectedArray = array('B','D','F');
$wordList = array();
foreach($selectedArray as $words){
$wordList[] = $globalWordArray[$words][rand(0,count($globalWordArray[$words])-1];
}
This could be a solution:
$letters = array(
'A' => array('WORD1','WORD2','WORD3'),
'B' => array('WORD1','WORD2','WORD3'),
'C' => array('WORD1','WORD2','WORD3'),
'D' => array('WORD1','WORD2','WORD3'),
'E' => array('WORD1','WORD2','WORD3'),
'F' => array('WORD1','WORD2','WORD3'),
'H' => array('WORD1','WORD2','WORD3'),
'G' => array('WORD1','WORD2','WORD3'),
);
$output = "FGH";
for ($i=0; $i < strlen($output); $i++) {
echo $output[$i] ." - (RANDOM WORD FOR ARRAY KEY " . $output[$i]." ";
echo $letters[$output[$i]][array_rand($letters[$output[$i]])] .")" . "<br />";
}
Output is:
F - (RANDOM WORD FOR ARRAY KEY F WORD3)
G - (RANDOM WORD FOR ARRAY KEY G WORD3)
H - (RANDOM WORD FOR ARRAY KEY H WORD1)
Your logic looks wrong where you are actually performing the randomisation, see comments in your code below
$result = array();
foreach($chars as $char){
$random_key = array_rand($words[$char]);
$key = $words[$char][$random_key]; // This is a value at this point yet you named it key
unset($words[$char][$random_key]);
$result[$key] = $char; // This will create an entry in result such as $result['WORD 1'] = 'F', I'm sure thats wrong
}
Fixed version below
$result = array();
foreach($chars as $char){
$random_key = array_rand($words[$char]);
$value = $words[$char][$random_key];
unset($words[$char][$random_key]);
$result[$char] = $value;
}
What you have suggested you want is commonly referred to as a Shuffle Bag (http://kaioa.com/node/89). Shuffle Bags allow you to fill up collections with items and then pick them out randomly until the collection runs out of items. Think of it like the Bag of letters in Scrabble. There is a PHP implementation in the link above.
Using that sort of implementation would turn your foreach loop to this:
$result = array();
foreach($chars as $char){
$result[$char] = $words[$char]->next();
}