I want to create PHP function to encode any string just with following rule.
a=1; b=2; c=3;.....y=25;z=26;
for eg.
If my string is "abc" then my encoded data will be "123".
We can use $key=>$value array but it will iterate 26 times for every letter!!
Use some delimiter so that you can identify separate characters. You can try this.
$chars = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4);
$str = "acd";
$encoded = array();
for ($i = 0; $i < strlen($str); $i++) {
$encoded[] = $chars[$str[$i]];
}
echo implode('|', $encoded);
Output
1|3|4
function encodedString($your_string)
$alpha_arr = range("A", "Z");
$your_string = strtoupper($your_string);
$encoded = "";
for($i=0; $i<strlen($your_string); $i++)
{
$strOne = substr($your_string, $i, 1);
if (in_array($strOne, $alpha_arr))
{
$encoded .= array_search($strOne, $alpha_arr)+1;
}
}
return $encoded;
}
You should have a padded encoding number to avoid confusions, with an array such as:
$converter = array('a' => '01', 'b' => '02' ...);
then go through each letter of the original string and construct your encoded string accessing the $converter array by key ('a', 'b' ... 'z').
you can also use str_replace to loop through the converter array and replace each character. Using str_replace you have at most N iterations, where N is the number of items in the converter array, regardless of the original string dimension.
The ord() method outputs the ascii value. now you can subtract 64 and 96 based on the text case to get the corresponding values. You will need no iterations or loop or anything. use a change case function and get the ascii value. the subtract the constant.
More details about ord method here
Related
I would like to ask if it is possible to cut a word like
"Keyboard" in multiple strings, in PHP?
I want the string to be cut whenever a / is in it.
Example:
String: "Key/boa/rd"
Now I want that the cut result look like this:
String1: "Key"
String2: "boa"
String3: "rd"
You can use the PHP explode function. So, if your string was "Key/boa/rd", you would do:
explode('/', 'Key/boa/rd');
and get:
[
"Key",
"boa",
"rd",
]
It's unclear from your question, but if you don't want an array (and instead would like variables) you can use array destructuring like so:
[$firstPart, $secondPart, $thirdPart] = explode('/', 'Key/boa/rd');
However, if the string only had one / then that approach could lead to an exception being thrown.
The answer by Nathaniel assumes that your original string contains / characters. It is possible that you only used those in your example and you want to split the string into equal-length substrings. The function for that is str_split and it looks like:
$substrings = str_split($original, 3);
That will split the string $original into an array of strings, each of length 3 (except the very last one if it doesn't divide equally).
You can travel through the line character by character, checking for your delimeter.
<?php
$str = "Key/boa/rd";
$i = $j = 0;
while(true)
{
if(isset($str[$i])) {
$char = $str[$i++];
} else {
break;
}
if($char === '/') {
$j++;
} else {
if(!isset($result[$j])) {
$result[$j] = $char;
} else {
$result[$j] .= $char;
}
}
}
var_export($result);
Output:
array (
0 => 'Key',
1 => 'boa',
2 => 'rd',
)
However explode, preg_split or strtok are probably the goto Php functions when wanting to split strings.
I need to change each character in a string but this change is include all possible results. Keys and Values of array variable can replace each other
for example list of all letter is similar to below
$changeList=array(
"ş"=>"s",
"ç"=>"c",
"i"=>"ı",
"ğ"=>"ğ",
"ü"=>"u",
"ö"=>"o",
"Ş"=>"S",
"Ç"=>"C",
"İ"=>"I",
"Ğ"=>"G",
"Ü"=>"U",
"Ö"=>"O"
);
$word="ağaç";
if I calculated correct , this is posible 2^2 = 4 results. (for ğ and ç letters)
after replace all letters , I need this results.
ağaç
agaç
ağac
agac
and other words example =pişir
this words include changeable three letter. 2^3 = 8 results. (for s,ı,ç 3 letters)
pişir
pışir
pisir
pişır
pişır
pisır
pısır
pışır
I need an array variable which contains all results. How can I do this , with best performance.
Okay, I became a little obsessed with this and decided to have a go (hey, it's Friday evening).
As I noted in the comment above, you want to generate a new word variation for each individual letter change - including letters that occur more than once. Another tricky consideration is multibyte characters.
What follows is an attempt an an answer that is probably pretty sub-optimal but hopefully gets the job done... I'm sure there are many ways to improve this but it's a start that you might be able to iterate on:
<?php
// this solution assumes UTF-8 config settings in php.ini
// setting them with ini_set() seems to work also but ymmv
ini_set('default_charset', 'UTF-8');
ini_set('mbstring.internal_encoding', 'UTF-8');
function getWordReplacements($word, $replacements) {
// $results... add the original
$results = array($word);
// multibyte split of $word
// credit: http://stackoverflow.com/a/2556753/312962
$chars = preg_split('//u', $word, -1, PREG_SPLIT_NO_EMPTY);
// we will iterate over the chars and create replacements twice,
// first pass is a forward pass, second is a reverse pass
// we need a copy of the $chars array for each pass
$forwardPass = $chars;
$reversePass = $chars;
// how many chars in the word?
$length = count($chars);
// we'll store the index of the first character
// that has a copy in the $replacements list for later
$first = null;
// first pass... iterate!
for ($i = 0; $i < $length; $i++) {
// is the current character in the $replacements list?
if (array_key_exists($chars[$i], $replacements)) {
// save the index of the first match
if (is_null($first)) {
$first = $i;
}
// replace the found char with the translation
$forwardPass[$i] = $replacements[$forwardPass[$i]];
// flatten the result and save it as a variation
$results[] = implode($forwardPass);
}
}
// second pass... same as the first pass except:
// * we go backwards through the array
// * we stop before we reach the $first index, to avoid a duplicate
// entry of the first variation saved in the first pass...
for ($j = ($length - 1); $j > $first; $j--) {
if (array_key_exists($chars[$j], $replacements)) {
$reversePass[$j] = $replacements[$reversePass[$j]];
$results[] = implode($reversePass);
}
}
// return the results
return $results;
}
// test with a subset replacement list
$list = [
'ç' => 'c',
'ğ' => 'g',
'ş' => 's',
'i' => 'ı',
];
// a couple of examples
$r1 = getWordReplacements('pişir', $list);
$r2 = getWordReplacements('ağaç', $list);
var_dump($r1, $r2);
Yields:
array (size=6)
0 => string 'pişir' (length=6)
1 => string 'pışir' (length=7)
2 => string 'pısir' (length=6)
3 => string 'pısır' (length=7)
4 => string 'pişır' (length=7)
5 => string 'pisır' (length=6)
array (size=4)
0 => string 'ağaç' (length=6)
1 => string 'agaç' (length=5)
2 => string 'agac' (length=4)
3 => string 'ağac' (length=5)
Hope this helps :)
I have an array that contains values of 1 or 0 representing true or false values. e.g.
array(1,0,0,1,0,1,1,1,1);
I want to compress/encode this array into the shortest string possible so that it can be stored within a space constrained place such as a cookie. It also need to be able to be decoded again later. How do I go about this?
ps. I am working in PHP
Here is my proposal:
$a = array(1,0,0,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1,1,0,0,1,0,1,1,1,1);
$compressed = base64_encode(implode('', array_map(function($i) {
return chr(bindec(implode('', $i)));
}, array_chunk($a, 8))));
var_dump($compressed); // string(8) "l8vlBw=="
So you get each 8 characters (which in fact is a binary 0..255), convert them to an integer, represent as an ASCII character, implode it to a string and convert to base64 to be able to save it as a string.
UPD:
the opposite is pretty straightforward:
$original = str_split(implode('', array_map(function($i) {
return decbin(ord($i));
}, str_split(base64_decode($compressed)))));
How exactly I wrote it (just in case anyone interesting how to write such unreadable and barely maintainable code):
I've written the $original = $compressed; and started reversing the right part of this expression step by step:
Decoded from base64 to a binary string
Split it to an array
Converted every character to its ASCII code
Converted decimal ASCII code to a binary
Joined all the binary numbers into a single one
Split the long binary string to an array
Dont use serialize. Just make a string of it:
<?php
$string = implode( '', $array );
?>
You are left with an string like this:
100101111
If you want to have an array again, just access it like an array:
$string = '100101111';
echo $string[1]; // returns "0"
?>
Of course you could also make it a decimal and just store the number. That's even shorter then the "raw" bits.
<?php
$dec = bindec( $string );
?>
How about pack and unpack
$arr = array(1,1,1,1,0,0,1,1,0,1,0,0,1,1,0,0,1,1,1,1);
$str = implode($arr);
$res = pack("h*", $str);
var_dump($res);
$rev = unpack("h*", $res);
var_dump($rev);
output:
string(10) # Not visible here
array(1) {
[1]=>
string(20) "11110011010011001111"
}
Here is my solution based on zerkms answer, this deals with the loss of leading 0's when converting decimals back into binary.
function compressBitArray(array $bitArray){
$byteChunks = array_chunk($bitArray, 8);
$asciiString = implode('', array_map(function($i) {
return chr(bindec(implode('', $i)));
},$byteChunks));
$encoded = base64_encode($asciiString).'#'.count($bitArray);
return $encoded;
}
//decode
function decompressBitArray($compressedString){
//extract origional length of the string
$parts = explode('#',$compressedString);
$origLength = $parts[1];
$asciiChars = str_split(base64_decode($parts[0]));
$bitStrings = array_map(function($i) {
return decbin(ord($i));
}, $asciiChars);
//pad lost leading 0's
for($i = 0; $i < count($bitStrings); $i++){
if($i == count($bitStrings)-1){
$toPad = strlen($bitStrings[$i]) + ($origLength - strlen(implode('', $bitStrings)));
$bitStrings[$i] = str_pad($bitStrings[$i], $toPad, '0', STR_PAD_LEFT);
}else{
if(strlen($bitStrings[$i]) < 8){
$bitStrings[$i] = str_pad($bitStrings[$i], 8, '0', STR_PAD_LEFT);
}
}
}
$bitArray = str_split(implode('', $bitStrings));
return $bitArray;
}
I have string:
ABCDEFGHIJK
And I have two arrays of positions in that string that I want to insert different things to.
Array
(
[0] => 0
[1] => 5
)
Array
(
[0] => 7
[1] => 9
)
Which if I decided to add the # character and the = character, it'd produce:
#ABCDE=FG#HI=JK
Is there any way I can do this without a complicated set of substr?
Also, # and = need to be variables that can be of any length, not just one character.
You can use string as array
$str = "ABCDEFGH";
$characters = preg_split('//', $str, -1);
And afterwards you array_splice to insert '#' or '=' to position given by array
Return the array back to string is done by:
$str = implode("",$str);
This works for any number of characters (I am using "#a" and "=b" as the character sequences):
function array_insert($array,$pos,$val)
{
$array2 = array_splice($array,$pos);
$array[] = $val;
$array = array_merge($array,$array2);
return $array;
}
$s = "ABCDEFGHIJK";
$arr = str_split($s);
$arr_add1 = array(0=>0, 1=>5);
$arr_add2 = array(0=>7, 1=>9);
$char1 = '#a';
$char2 = '=b';
$arr = array_insert($arr, $arr_add1[0], $char1);
$arr = array_insert($arr, $arr_add1[1] + strlen($char1), $char2);
$arr = array_insert($arr, $arr_add2[0]+ strlen($char1)+ strlen($char2), $char1);
$arr = array_insert($arr, $arr_add2[1]+ strlen($char1)+ strlen($char2) + strlen($char1), $char2);
$s = implode("", $arr);
print_r($s);
There is an easy function for that: substr_replace. But for this to work, you would have to structure you array differently (which would be more structured anyway), e.g.:
$replacement = array(
0 => '#',
5 => '=',
7 => '#',
9 => '='
);
Then sort the array by keys descending, using krsort:
krsort($replacement);
And then you just need to loop over the array:
$str = "ABCDEFGHIJK";
foreach($replacement as $position => $rep) {
$str = substr_replace($str, $rep, $position, 0);
}
echo $str; // prints #ABCDE=FG#HI=JK
This works by inserting the replacements starting from the end of string. And it would work with any replacement string without having to determine the length of that string.
Working DEMO
Say I have a string of 16 numeric characters (i.e. 0123456789012345) what is the most efficient way to delimit it into sets like : 0123-4567-8901-2345, in PHP?
Note: I am rewriting an existing system that is painfully slow.
Use str_split():
$string = '0123456789012345';
$sets = str_split($string, 4);
print_r($sets);
The output:
Array
(
[0] => 0123
[1] => 4567
[2] => 8901
[3] => 2345
)
Then of course to insert hyphens between the sets you just implode() them together:
echo implode('-', $sets); // echoes '0123-4567-8901-2345'
If you are looking for a more flexible approach (for e.g. phone numbers), try regular expressions:
preg_replace('/^(\d{4})(\d{4})(\d{4})(\d{4})$/', '\1-\2-\3-\4', '0123456789012345');
If you can't see, the first argument accepts four groups of four digits each. The second argument formats them, and the third argument is your input.
This is a bit more general:
<?php
// arr[string] = strChunk(string, length [, length [...]] );
function strChunk() {
$n = func_num_args();
$str = func_get_arg(0);
$ret = array();
if ($n >= 2) {
for($i=1, $offs=0; $i<$n; ++$i) {
$chars = abs( func_get_arg($i) );
$ret[] = substr($str, $offs, $chars);
$offs += $chars;
}
}
return $ret;
}
echo join('-', strChunk('0123456789012345', 4, 4, 4, 4) );
?>