I have a dictionary like
UUU F
UUC F
CUU L
CUC L
UUA L
CUA L
UUG L
CUG L
AUU I
AUC I
AUA I
GUU V
GUC V
GUG V
GUA V
So Given a string I want to replace every 3 chars its respective char
I was thinking on using associative arrays:
$d = array();
$d['UUU']='F';
$d['UUC']='F';
$d['UUA']='L';
$d['CUU']='L';
$d['GUC']='V';
$d['GUG']='V';
$d['GUA']='V';
$d['UUG']='L';
$d['CUG']='L';
$s = "UUAGUAUUG";
$temp="";
for($i=0; $i<strlen($s)+1; $i++){
$temp .= $s[$i];
if($i%3==0){
echo $temp;
echo array_search($temp, $d);
$temp = "";
}
}
It should output LVL but have no success
Use str_split:
$s = 'UUAGUAUUG';
$split = str_split($s,3);
$translated = array();
foreach ($split as $bases) {
/**
* # supresses warnings if the array index doesn't exist
*/
$translated []= #$d[$bases];
}
echo join('',$translated);
I think this might work:
$temp = implode(array_map(function($a) { return $d[$a];}, str_split($s, 3)));
The basic solution is:
<?php
$dict = array(
'UUU' => 'F',
'UUC' => 'F',
'UUA' => 'L',
'CUU' => 'L',
'GUC' => 'V',
'GUG' => 'V',
'GUA' => 'V',
'UUG' => 'L',
'CUG' => 'L'
);
$before = "UUAGUAUUG";
$after = strtr($before, $dict);
Although you may be able to write a faster version that takes into account that you are replacing every three letters.
And I'm not 100% sure this will even work, given what kind of combinations can overlap over the 3-char barrier. Which leaves you with this rotten solution:
$after = str_replace('-', '',
strtr(preg_replace('/[A-Z]{3}/', '\0-', $before), $dict));
Seriously, don't try this at home. ;)
You're testing at the wrong time.
Change $i%3 == 0 to $i%3 == 2.
The reason here is that you have added to your temporary string first. That means you immediately check a string of length 1 ("U") and then clear it. Then you go around for another 3 times and you get "UAG", followed by "UAU". Neither of these are in your array.
What I don't understand is that you output the value of $temp each time this happens, so you should have picked up on this.
Change your for loop to this:
for($i=0; $i<strlen($s)+1; $i++){
$temp .= $s[$i];
if(($i+1)%3==0){
echo $d[$temp];
$temp = "";
}
}
Your i value starts from 0. And array_values does not give the expected answer.
Related
Given a custom alphabet like ['f', 'h', 'z', '#', 's']
I'd like to take a string written in this "alphabet" like
ffff#zz and increment it
So for example if the string was sss After incrementing it will look like hfff the same way that if you increment 999 you get 1000
My current attempt is here: https://3v4l.org/FjAsd
Given:
$characters = ['a', 'b', 'c'];
$string = 'cccc';
my code can do:
baaaa
but if give it
$characters = ['a', 'b', 'c'];
$string = 'aaa';
it will return
b
When I expected aab
The way this works is by processing the string from the end, each time you look at a character you check it's position in the array (I use a flipped array as it's more efficient than using array_search() each time). Then if the character is at the end of the array, then set it to the 0th element of the alphabet and increment the next digit to the left. If there is another letter from the alphabet to increment the current value, then just replace it and stop the loop.
The last bit is that if you have processed every character and the loop was still going, then there is a carry - so add the 0th digit to the start.
$characters = ['a', 'b', 'c'];
$string = 'cccc';
$index = array_flip($characters);
$alphabetCount = count($index)-1;
for ( $i = strlen($string)-1; $i >= 0; $i--) {
$current = $index[$string[$i]]+1;
// Carry
if ( $current > $alphabetCount ) {
$string[$i] = $characters[0];
}
else {
// update and exit
$string[$i] = $characters[$current];
break;
}
}
// As reached end of loop - carry
if ( $i == -1 ) {
$string = $characters[0].$string;
}
echo $string;
gives
aaaaa
with
$characters = ['f', 'h', 'z', '#', 's'];
$string = 'ffff#zz';
you get
ffff#z#
I ended up with something like this:
$string = 'ccc';
$alphabet = ['a', 'b', 'c'];
$numbers = array_keys($alphabet);
$numeric = str_replace($alphabet, $numbers, $string);
$base = count($alphabet) + 1;
$decimal = base_convert($numeric, $base, 10);
$string = base_convert(++$decimal, 10, $base);
strlen($decimal) !== strlen($string)
and $string = str_replace('0', '1', $string);
echo str_replace($numbers, $alphabet, $string);
This one has the advantage of supporting multi byte characters
I'm trying to split the string MTWTHFS (days of the week) and store it as an array.
I've tried str_split() but it will also split T and H for Thursday.
if(strpos($days, 'TH') !== false) {
$withth = str_replace("TH", "" ,$days);
}else{
$day = str_split($days);
print_r($day);
}
I also tried first removing the TH in the string before splitting it.
str_split() is fine when there is no TH in the string.
This is my desired result:
array([0]=>'M', [1]=>'T', [2]=>'W', [3]=>'TH', [4]=>'F', [5]=>'S')
Are there any better ways to do this?
I'm sure there will be a few ways to do this. Here is one way with preg_split()
Code: (PHP Demo)
$days = 'MTWTHFS';
$split = preg_split('/.H?\K/', $days, 0, PREG_SPLIT_NO_EMPTY);
var_export($split);
Output:
array (
0 => 'M',
1 => 'T',
2 => 'W',
3 => 'TH',
4 => 'F',
5 => 'S',
)
Pattern Demo
For anyone who wishes to use a non-regex method for any reason, this will do the same:
$days = 'MTWTHFS';
for ($i = 0, $k = -1, $len = strlen($days); $i < $len; ++$i) {
if ($days[$i] == 'H') {
$split[$k] .= 'H';
} else {
$split[++$k] = $days[$i];
}
}
It seems PHP 5.5 doesn't like \K in the pattern. This will provide the desired result:
$split = preg_split('/(.H?)/', $days, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
I'm working with my code that will allow the user to input a word and each letter of the word will give a meaning.
Example: User inputted a text "APPLE".
Output:
A - arc
P - priest
P - president
L - lion
E - escape
The meaning of every letter will be in array..
I already have my code here but the meaning are repeated.
Example:
A - **Arrow**
L - Love
A - **Arrow**
S - Soul
Here's my code
<?php
$chars = str_split("APPLE");
foreach($chars as $char){
if (substr($char, 0, 1) === 'A')
{
$meaning = array("Angel","Ancient","Arrow");
echo $meaning[array_rand($meaning)];
}
}
?>
You could unset it temporarily inside the loop so that you won't get dups. Example:
$chars = str_split("APPLE");
$words = array(
// its up to you what words you want to map
'A' => array("Angel","Ancient","Arrow"),
'E' => array('Elephat', 'Eardrum'),
'L' => array('Level', 'Laravel', 'Love'),
'S' => array('Sweet', 'Spicy', 'Savy'),
'P' => array('Powerful', 'Predictable', 'Pass', 'piss')
);
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
echo "$char - $key <br/>";
}
You could save a "cache" array of previously used terms. Example:
<?php
$chars = str_split("APPLE");
$used_terms = array();
foreach($chars as $char){
if (substr($char, 0, 1) === 'A') {
$meaning = array("Angel","Ancient","Arrow");
do {
$term = $meaning[array_rand($meaning)];
} while (in_array($term, $used_terms));
$used_terms[] = $term;
echo $term;
}
}
?>
I am quite a newbie when it comes to php and i wanted to try something but i have absolutely no idea how should i do this.. To be honest i am not sure if can explain this to you very clearly either.. Lets get started..
I have couple of letters for example a, b, c, d and e..
and for each one of them i have couples of two-charactered values like this:
a -> fg, dz, gc, bg
b -> zt, hg, oq, vg, gb
c -> lt, pr, cs, sh, pr
d -> kt, nt, as, pr
e -> zd, ke, cg, sq, mo, ld
Here comes the question:
I would like to get a random value for each time for example: dcbae
and for this the ultimate output should be something like this: ntshztdzld or asltvggcmo..
(After generating a random string with the charachters above (between a-e), i should generate another string that contains random values those are related with the each character..
This is not a homework or something similar.
Thanks in advance for your understanding..
Well, you would first create a map:
$map = Array(
"a" => Array("fg","dz","gc","bg"),
"b" => Array("zt","hg","oq","vg","gb"),
"c" => Array("lt","pr","cs","sh","pr"),
"d" => Array("kt","nt","as","pr"),
"e" => Array("zd","ke","cg","sq","mo","ld")
);
I notice that you have the same pair "pr" several times - if you want this encoding to be reversible, avoid duplicates.
Anyway, once you have that it's easy enough to loop through your input string and get a random output:
$input = "dcbae";
$len = strlen($input);
$output = "";
for( $i=0; $i<$len; $i++) {
$entry = &$map[$input[$i]];
if( isset($entry)) $output .= $entry[mt_rand(0,count($entry)-1)];
else $output .= "??";
}
$output is the result.
<?php
// Setup matching values
$encpairs[ 'a' ] = array( 'fg', 'dz', 'gc', 'bg' );
$encpairs[ 'b' ] = array( 'zt', 'hg', 'oq', 'vg', 'gb' );
$encpairs[ 'c' ] = array( 'lt', 'pr', 'cs', 'sh', 'pr' );
// etc. etc.
// Define input string
$my_string = 'abc';
// To randomly build input string
$my_string = '';
$last_key = '';
$key = '';
$keys = array_keys( $encpairs );
$ttl_keys = count( $keys ) -1;
// Generate the input string at random; change "5" to length you desire
for ( $j=0; $j < 5; $j++ ){
// Randomly select a key from $encpairs array (giving you one letter at random)
// The while loop ensures no two letters are used consecutively
while ( $key == $last_key ) {
$key =$keys[ rand(0, $ttl_keys ) ];
}
$last_key = $key;
$my_string .= $key;
}
// Determine input string length
$length = strlen( $my_string );
// Loop through each letter
$output = '';
for( $i=0; $i < $length; $i++ ){
shuffle( $encpairs[ $my_string[$i] ] );
$output.= $encpairs[ $my_string[$i] ][0]; // Added [0]
}
Start by initializing a second string outside of the loop. Convert your original string (to be encrypted) into an array, and then loop through the whole array and append to the second string.
So you get
$splitstr=str_split($original);
$final_string="";
$map=Array(/**/);
foreach($splitstr as $char)
{
$final_string.=$map[$char][rand(0,count($map[$char])-1)];
}
return $final_string;
I have a set of strings, each string has a variable number of segments separated by pipes (|), e.g.:
$string = 'abc|b|ac';
Each segment with more than one char should be expanded into all the possible one char combinations, for 3 segments the following "algorithm" works wonderfully:
$result = array();
$string = explode('|', 'abc|b|ac');
foreach (str_split($string[0]) as $i)
{
foreach (str_split($string[1]) as $j)
{
foreach (str_split($string[2]) as $k)
{
$result[] = implode('|', array($i, $j, $k)); // more...
}
}
}
print_r($result);
Output:
$result = array('a|b|a', 'a|b|c', 'b|b|a', 'b|b|c', 'c|b|a', 'c|b|c');
Obviously, for more than 3 segments the code starts to get extremely messy, since I need to add (and check) more and more inner loops. I tried coming up with a dynamic solution but I can't figure out how to generate the correct combination for all the segments (individually and as a whole). I also looked at some combinatorics source code but I'm unable to combine the different combinations of my segments.
I appreciate if anyone can point me in the right direction.
Recursion to the rescue (you might need to tweak a bit to cover edge cases, but it works):
function explodinator($str) {
$segments = explode('|', $str);
$pieces = array_map('str_split', $segments);
return e_helper($pieces);
}
function e_helper($pieces) {
if (count($pieces) == 1)
return $pieces[0];
$first = array_shift($pieces);
$subs = e_helper($pieces);
foreach($first as $char) {
foreach ($subs as $sub) {
$result[] = $char . '|' . $sub;
}
}
return $result;
}
print_r(explodinator('abc|b|ac'));
Outputs:
Array
(
[0] => a|b|a
[1] => a|b|c
[2] => b|b|a
[3] => b|b|c
[4] => c|b|a
[5] => c|b|c
)
As seen on ideone.
This looks like a job for recursive programming! :P
I first looked at this and thought it was going to be a on-liner (and probably is in perl).
There are other non-recursive ways (enumerate all combinations of indexes into segments then loop through, for example) but I think this is more interesting, and probably 'better'.
$str = explode('|', 'abc|b|ac');
$strlen = count( $str );
$results = array();
function splitAndForeach( $bchar , $oldindex, $tempthread) {
global $strlen, $str, $results;
$temp = $tempthread;
$newindex = $oldindex + 1;
if ( $bchar != '') { array_push($temp, $bchar ); }
if ( $newindex <= $strlen ){
print "starting foreach loop on string '".$str[$newindex-1]."' \n";
foreach(str_split( $str[$newindex - 1] ) as $c) {
print "Going into next depth ($newindex) of recursion on char $c \n";
splitAndForeach( $c , $newindex, $temp);
}
} else {
$found = implode('|', $temp);
print "Array length (max recursion depth) reached, result: $found \n";
array_push( $results, $found );
$temp = $tempthread;
$index = 0;
print "***************** Reset index to 0 *****************\n\n";
}
}
splitAndForeach('', 0, array() );
print "your results: \n";
print_r($results);
You could have two arrays: the alternatives and a current counter.
$alternatives = array(array('a', 'b', 'c'), array('b'), array('a', 'c'));
$counter = array(0, 0, 0);
Then, in a loop, you increment the "last digit" of the counter, and if that is equal to the number of alternatives for that position, you reset that "digit" to zero and increment the "digit" left to it. This works just like counting with decimal numbers.
The string for each step is built by concatenating the $alternatives[$i][$counter[$i]] for each digit.
You are finished when the "first digit" becomes as large as the number of alternatives for that digit.
Example: for the above variables, the counter would get the following values in the steps:
0,0,0
0,0,1
1,0,0 (overflow in the last two digit)
1,0,1
2,0,0 (overflow in the last two digits)
2,0,1
3,0,0 (finished, since the first "digit" has only 3 alternatives)