I came across Decode string problem which is given an encoded string s, decode it With rule:
N[encoded] => encoded*N.
Examples:
$input = "4[abc]";
// output: abcabcabcabc
$input = "ac3[ab]d";
// output: acabababd
$input = "a2[b3[cd]]";
// output: abcdcdcdbcdcdcd
I have tried solving it, using string manipulation with if conditions, It works only for two inputs, However it fails at last one when the given input has multiple encoded string.
$output = '';
$arr = str_split($input);
for ($i=0; $i < count($arr); $i++) {
$char = $arr[$i];//current character
if($char == '['){
$closed = strpos($input, ']');
$len = $closed - ($i+1);
$output .= str_repeat(substr($input, $i+1, $len), $prev);
$i = strpos($input, ']');
}elseif(ctype_digit($char)){
$prev = $char;
}else{
$output .= $char;
}
}
echo $output;
Is there any ways to solving it using this approach or another. Or only can be solved using stack?
Thank you for any idea can help solving this problem!
To solve nested [], you have to decode from the inside out. The solution uses preg_replace_callback until there is nothing left to replace.
function fkdecode($str){
while(true){
$newStr = preg_replace_callback('~(\d+)\[([^\[\]]+)\]~',
function($m){
return str_repeat($m[2],(int)$m[1]);
},
$str);
if($newStr == $str) break;
$str = $newStr;
}
return $str;
}
//test
$inputs = ["4[abc]", // output: abcabcabcabc
"ac3[ab]d", // output: acabababd
"a2[b3[cd]]", // output: abcdcdcdbcdcdcd
];
foreach($inputs as $input){
echo $input.' := '. fkdecode($input)."<br>\n";
}
Output:
4[abc] := abcabcabcabc
ac3[ab]d := acabababd
a2[b3[cd]] := abcdcdcdbcdcdcd
Use strpos() with offset ($i in your case) specified to decode multiple encoded string.
You could've used strlen instead of count. It's to avoid array to string conversion error. Also, you should take into consideration the case when N > 9.
$output = '';
for ($i = 0; $i < strlen($input); $i++) {
$char = $input[$i];//current character
if($char == '['){
$closed = strpos($input, ']', $i);
$len = $closed - ($i+1);
$output .= str_repeat(substr($input, $i+1, $len), $prev);
$i = strpos($input, ']', $i);
}elseif(ctype_digit($char)){
$end = strpos($input, '[', $i);
$len = $end - $i;
$prev = substr($input, $i, $len);
$i = strpos($input, '[', $i) - 1;
}else{
$output .= $char;
}
}
echo $output;
?>
BTW, this doesn't solve the nested []. You could use a stack to solve it. Hint: Check if there's a [ before $closed. Or use this non-O(n) approach.
I was asked this question in a recent interview.
A string contains a-z, A-Z and spaces. Sort the string so that all lower cases are at the beginning, spaces in the middle and upper cases at the end. Original order among lower and upper cases needs to remain the same. This is what I came up with:
$str = "wElComE to CaLiFOrNiA";
$lowercase ="";
$uppercase="";
$spaces="";
for ($i=0 ; $i <= strlen($str)-1 ; $i++)
{
if ($str[$i] <= 'z' && $str[$i] >= 'a' )
{
$lowercase .=$str[$i];
}
else if (($str[$i] <= 'Z' && $str[$i] >= 'A'))
{
$uppercase .=$str[$i];
}
else
{
$spaces.=$str[$i];
}
}
echo $lowercase.$spaces.$uppercase;
input: wElComE to CaLiFOrNiA
output: wlomtoairi ECECLFONA
I'm wondering if there are better ways to do this? And there are 2 spaces in the input string, and the output shows only one space. The complexity of this is O(N) right.
Any ideas?
I'm sure there are many ways to do this. You could do it with regular expressions..
$str = "wElComE to CaLiFOrNiA";
preg_match_all('~([a-z])~', $str, $lowercase);
preg_match_all('~([A-Z])~', $str, $uppercase);
preg_match_all('~(\h)~', $str, $spaces);
echo implode('', $lowercase[1]) . implode('', $spaces[1]) . implode('', $uppercase[1]);
Output:
wlomtoairi ECECLFONA
When you say better are you referring to performance, readability, or something else?
Second regex approach:
$str = "wElComE to CaLiFOrNiA";
echo preg_replace('~[^a-z]~', '', $str) . preg_replace('~[^\h]~', '', $str) . preg_replace('~[^A-Z]~', '', $str);
I think your solution is pretty OK, but if you are into micro-optimization you could make some minor changes. The following is faster than the regular expression solutions above (benchmark run 10000 times) at least on my system:
$str = "wElComE to CaLiFOrNiA";
$lowercase = "";
$uppercase = "";
$spaces = "";
$end = strlen($str); // Calculate length just once
for ($i = 0; $i < $end; $i++) {
$c = $str[$i]; // Get $str[$i] once
// We know there are only A-Z, a-z and space chars so we
// only need a greater-than check ('a' > 'A' > ' ')
if ($c >= 'a') {
$lowercase .= $c;
} else if ($c >= 'A') {
$uppercase .= $c;
} else
$spaces .= $c;
}
echo $lowercase . $spaces . $uppercase, PHP_EOL;
function sortString($string)
{
$string_chars = str_split($string);
$output = ['', '', ''];
foreach ($string_chars as $char) {
$output[$char === ' ' ? 1 : ($char === ucfirst($char) ? 2 : 0)] .= $char;
}
return implode('', $output);
}
echo sortString("wElComE to CaLiFOrNiA");
Gives wlomtoairi ECECLFONA
Some time ago during a job interview I got the task to reverse a string in PHP without using strrev.
My first solution was something like this:
$s = 'abcdefg';
$temp = '';
for ($i = 0, $length = mb_strlen($s); $i < $length; $i++) {
$temp .= $s{$length - $i - 1};
}
var_dump($temp);
// outputs string(7) "gfedcba"
then they asked me if I could do this without doubling the memory usage (not using the $temp variable or any variable to copy the reversed string to) and I failed.
This kept bugging me and since then I tried to solve this multiple times but I constantly failed.
My latest try looks like this:
$s = 'abcdefg';
for ($i = 0, $length = mb_strlen($s); $i < $length; $i++) {
$s = $s{$i * 2} . $s;
}
var_dump($s);
// outputs string(14) "gfedcbaabcdefg"
It's not a solution to chop off "abcdefg" after the loop because then I would still double the amount of memory used. I need to remove the last character in every iteration of the loop.
I tried to use mb_substr like this:
$s = 'abcdefg';
for ($i = 0, $length = mb_strlen($s); $i < $length; $i++) {
$s = $s{$i * 2} . mb_substr($s, $length - $i - 1, 1);
}
var_dump($s);
but it only gives me Uninitialized string offset errors.
This is where I'm stuck (again). I tried googling but all the solutions I found either echo the characters directly or use a temporary variable.
I also found the Question PHP String reversal without using extra memory but there's no answer that fits my needs.
That's an interesting one.
Here's something I just came up with:
$s = 'abcdefghijklm';
for($i=strlen($s)-1, $j=0; $j<$i; $i--, $j++) {
list($s[$j], $s[$i]) = array($s[$i], $s[$j]);
}
echo $s;
list() can be used to assign a list of variables in one operation. So what I am doing is simply swapping characters (starting with first and last, then second-first and second-last and so on, till it reaches the middle of the string)
Output is mlkjihgfedcba.
Not using any other variables than $s and the counters, so I hope that fits your criteria.
You can use the fact that in PHP a string can be thought of as an array of characters.
Then basically what you want to do is to replace each character $i on the left side of the middle of the string with the character $j on the right side of the middle with the same distance.
For example, in a string of seven characters the middle character is on position 3. The character on position 0 (distance 3) needs to be swapped with the character on position 6 (3 + 3), the character on position 1 (distance 2) needs to be swapped with the character on position 5 (3 + 2), etc.
This algorithm can be implemented as follows:
$s = 'abcdefg';
$length = strlen($s);
for ($i = 0, $j = $length-1; $i < ($length / 2); $i++, $j--) {
$t = $s[$i];
$s[$i] = $s[$j];
$s[$j] = $t;
}
var_dump($s);
$string = 'abc';
$reverted = implode(array_reverse(str_split($string)));
You could use the XOR swap trick.
function rev($str) {
$len = strlen($str);
for($i = 0; $i < floor($len / 2); ++$i) {
$str[$i] = $str[$i] ^ $str[$len - $i - 1];
$str[$len - $i - 1] = $str[$i] ^ $str[$len - $i - 1];
$str[$i] = $str[$i] ^ $str[$len - $i - 1];
}
return $str;
}
print rev("example");
Try this:
$s = 'abcdefg';
for ($i = strlen($s)-1; $i>=0; $i--) {
$s .= $s[$i];
$s[$i] = NULL;
}
var_dump(trim($s));
Here it is PHP7 version of this:
echo "\u{202E}abcdefg"; // outs: gfedcba
PHP strings are kinda-sorta mutable, but due to copy-on-write it's very difficult to modify them in-place without a copy being made. Some of the above solutions work, but only because they're stand-alone; some already fail because they define a function without a pass-by-reference argument. To get the code to actually operate in-place in a larger program, you'd need to pay careful attention to assignments, function arguments, and scopes.
Example:
$string1 = 'abc';
$string2 = $string1;
$string1[0] = 'b';
print("$string1, $string2");
> "abc, bbc"
I suppose that if between initializing the variable and modifying it you only ever used by-reference assignments (&=) and reference arguments (function rev(&$string)) (or assign the string to an object property initially, and then never assign it to any other variable), you might be able to change the original value of the string without making any copies. That's a bit ridiculous, however, and I'd assume that the interviewer who came up with that question didn't know about copy-on-write.
This isn't quite the same as immutability in other languages, by the way, because it applies to arrays too:
$a = [0, 1, 2];
$b = $a;
$b[0] = 1;
print(implode($a).implode($b));
> "012112"
To sum up, all types (except for objects as of PHP5) are assigned with copy-on-write unless you specifically use the &= operator. The assignment doesn't copy them, but unlike most other languages (C, Java, Python...) that either change the original value (arrays) or don't allow write access at all (strings), PHP will silently create a copy before making any changes.
Of course, if you switched to a language with more conventional pointers and also switched to byte arrays instead of strings, you could use XOR to swap each pair of characters in place:
for i = 0 ... string.length / 2:
string[i] ^= string[string.length-1-i]
string[string.length-1-i] ^= string[i]
string[i] ^= string[string.length-1-i]
Basically #EricBouwers answer, but you can remove the 2nd placeholder variable $j
function strrev2($str)
{
$len = strlen($str);
for($i=0;$i<$len/2;$i++)
{
$tmp = $str[$i];
$str[$i] = $str[$len-$i-1];
$str[$len-$i-1] = $tmp;
}
return $str;
}
Test for the output:
echo strrev2("Hi there!"); // "!ereht iH"
echo PHP_EOL;
echo strrev2("Hello World!"); // "!dlroW olleH"
This will go through the list and stop halfway, it swaps the leftmost and rightmost, and works it's way inward, and stops at the middle. If odd numbered, the pivot digit is never swapped with itself, and if even, it swaps the middle two and stops. The only extra memory used is $len for convenience and $tmp for swapping.
If you want a function that doesn't return a new copy of the string, but just edits the old one in place you can use the following:
function strrev3(&$str)
{
$len = strlen($str);
for($i=0;$i<$len/2;$i++)
{
$tmp = $str[$i];
$str[$i] = $str[$len-$i-1];
$str[$len-$i-1] = $tmp;
}
}
$x = "Test String";
echo $x; // "Test String"
strrev3($x);
echo PHP_EOL;
echo $x; // "gnirtS tseT"
Using &$str passes a direct pointer the the string for editing in place.
And for a simpler implementation like #treegardens, you can rewrite as:
$s = 'abcdefghijklm';
$len = strlen($s);
for($i=0; $i < $len/2; $i++) {
list($s[$i], $s[$len-$i-1]) = array($s[$len-$i-1], $s[$i]);
}
echo $s;
It has the similar logic, but I simplified the for-loop quite a bit.
Its Too Simple
//Reverse a String
$string = 'Basant Kumar';
$length = strlen($string);
for($i=$length-1;$i >=0;$i--){
echo $string[$i];
}
Here is my code to solve your problem
<?php
$s = 'abcdefg';
for ($i = 0, $length = mb_strlen($s); $i < $length; $i++) {
$s = $s{$i}.mb_substr($s,0,$i).mb_substr($s,$i+1);
}
var_dump($s);
?>
You could also use a recursion to reverse the string. Something like this for example:
function reverse($s) {
if(strlen($s) === 1) return $s;
return substr($s, strlen($s)-1) . reverse(substr($s , 0, strlen($s)-1));
}
What you do here is actually returning the last character of the string and then calling again the same function with the substring that contains the initial string without the last character. When you reach the point when your string is just one character then you end the recursion.
You can use this code to reverse a string without using the reserved function in php.
Code:
<?php
function str_rev($y)// function for reversing a string by passing parameters
{
for ($x = strlen($y)-1; $x>=0; $x--) {
$y .= $y[$x];
$y[$x] = NULL;
}
echo $y;
}
str_rev("I am a student");
?>
Output:
tneduts a ma I
In the above code, we have passed the value of the string as the parameter.We have performed the string reversal using for loop.
you could use substr with negative start.
Theory & Explanation
you can start with for loop with counter from 1 to length of string, and call substr inside iteration with counter * -1 (which will convert the counter into negative value) and length of 1.
So for the first time counter would be 1 and by multiplying with -1 will turn it to -1
Hence substr('abcdefg', -1, 1); will get you g
and next iteration substr('abcdefg', -2, 1); will get you f
and substr('abcdefg', -3, 1); will get you e
and so on ...
Code
$str = 'abcdefghijklmnopqrstuvwxyz';
for($i=1; $i <= strlen($str); $i++) {
echo substr($str, $i*-1, 1);
}
In Action: https://eval.in/583208
public function checkString($str){
if(!empty($str)){
$i = 0;
$str_reverse = '';
while(isset($str[$i])){
$strArr[] = $str[$i];
$i++;
}
for($j = count($strArr); $j>= 0; $j--){
if(isset($strArr[$j])){
$str_reverse .= $strArr[$j];
}
}
if($str == $str_reverse){
echo 'It is a correct string';
}else{
echo 'Invalid string';
}
}
else{
echo 'string not found.';
}
}
//Reverse String word by word
$str = "Reverse string word by word";
$i = 0;
while ($d = $str[$i]) {
if($d == " ") {
$out = " ".$temp.$out;
$temp = "";
}
else
$temp .= $d;
$i++;
}
echo $temp.$out;
The following solution is very simple, but it does the job:
$string = 'Andreas';
$reversedString = '';
for($i = mb_strlen($string) - 1; $i >= 0; $i--){
$reversedString .= $string[$i];
}
var_dump($reversedString) then results: string(7) "saerdnA"
<?php
$value = 'abcdefg';
$length_value = strlen($value);
for($i = $length_value-1; $i >=0 ;$i--){
echo $value[$i];
}
?>
you can try this..
$string = "NASEEM";
$total_word = strlen($string);
for($i=0; $i<=$total_word; $i++)
{
echo substr($string,$total_word-$i,1);
}
i have used some built in function but without str_rev function .
<?php
$text = "red";
$arr = str_split($text);
$rev_text = array_reverse($arr);
echo join(" ",$rev_text);
?>
Try This
<?php
$str="abcde";
for($i=strlen($str)-1;$i>=0;$i--){
echo $str[$i];
}
?>
output
edcba
This is my solution to solve this.
$in = 'This is a test text';
$out = '';
// find string length
$len = strlen($in);
// loop through it and print it reverse
for ( $i = $len - 1; $i >=0;$i-- )
{
$out = $out.$in[$i];
}
echo $out;
Reverse string using recursion function.
$reverseString = '';
function Reverse($str, $len)
{
if ($len == 0) {
return $GLOBALS['reverseString'];
} else {
$len--;
$GLOBALS['reverseString'] .= $str[$len];
return Reverse($str, $len);
}
}
$str = 'Demo text';
$len = strlen($str);
echo Reverse($str, $len)
Try this
$warn = 'this is a test';
$i=0;
while(#$warn[$i]){
$i++;}
while($i>0)
{
echo $warn[$i-1]; $i--;
}
Initially i had posted a question to find a solution to capitalize every other letter in a string. Thankfully Alex # SOF was able to offer a great solution, however ive been unable to get it to work with an array... To be clear what im trying to do in this case is explode quotes, capitalize every other letter in the array then implode them back.
if (stripos($data, 'test') !== false) {
$arr = explode('"', $data);
$newStr = '';
foreach($arr as $index => $char) {
$newStr .= ($index % 2) ? strtolower($char) : strtoupper($char);
}
$data = implode('"', $arr);
}
Using the anonymous function requires >= PHP 5.3. If not, just make the callback a normal function. You could use create_function(), but it is rather ugly.
$str = '"hello" how you "doing?"';
$str = preg_replace_callback('/"(.+?)"/', function($matches) {
$newStr = '';
foreach(str_split($matches[0]) as $index => $char) {
$newStr .= ($index % 2) ? strtolower($char) : strtoupper($char);
}
return $newStr;
}, $str);
var_dump($str);
Output
string(24) ""hElLo" how you "dOiNg?""
CodePad.
If you want to swap the case, swap the strtolower() and strtoupper() calls.
Is this what you're looking for?
foreach($data as $key => $val)
{
if($key%2==0) $data[$key] = strtoupper($data[$key]);
else $data[$key] = strtolower($data[$key]);
}
Or.... instead of using regular expression you could just not even use the explode method, and go with every other character and capitalize it. Here is an example:
$test = "test code here";
$count = strlen($test);
echo "Count = " . $count . '<br/>';
for($i = 0; $i < $count; $i++)
{
if($i % 2 == 0)
{
$test[$i] = strtolower($test[$i]);
}
else
{
$test[$i] = strtoupper($test[$i]);
}
}
echo "Test = " . $test;
The secret lies in the modulus operator. ;)
Edit: Dang, I just noticed the post above me by Jordan Arsenault already submitted this answer... I got stuck on the regex answer I missed that :-/ sorry Jordan, you were already on point.
Example of a string: "Some text.....!!!!!!!!?????"
Using PHP how would I get the position of the last letter (or even alphanum character) which in this example is the letter t?
You could use preg_match_all with the regular expression \p{L} to find all Unicode letters. With the additional flag PREG_OFFSET_CAPTURE you get also the offsets:
$str = "Some text.....!!!!!!!!?????";
if (preg_match_all('/\p{L}/u', $str, $matches, PREG_OFFSET_CAPTURE) > 0) {
$lastMatch = $matches[0][count($matches[0])-1];
echo 'last letter: '.$lastMatch[0].' at '.$lastMatch[1];
} else {
echo 'no letters found';
}
$s = "Some text.....!!!!!!!!embedded?????";
$words = str_word_count($s,2);
$lastLetterPos = array_pop(array_keys($words)) + strlen(array_pop($words)) - 1;
echo $lastLetterPos;
If you want to allow for alphanum rather than just alpha:
$s = "Some text.....!!!!!!!!embedded21?????";
$words = str_word_count($s,2,'0123456789');
$lastLetterPos = array_pop(array_keys($words)) + strlen(array_pop($words)) - 1;
echo $lastLetterPos;
To add other characters as valid:
$s = "Some text.....!!!!!!!!embedded!!à?????";
$words = str_word_count($s,2,'0123456789ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåæçèéêëìíîïðñòóôõöùúûüýÿ');
$lastLetterPos = array_pop(array_keys($words)) + strlen(array_pop($words)) - 1;
echo $lastLetterPos;
try substr() ;)
echo substr('abcdef', -1, 1);
It all depends on what you consider a letter, and what you want to do with "Some!!!???text???!!!" for example:
The naive solution would be to iterate from the last position in the string to find the first character you want to keep, then return that. (Or iterate from the beginning to find the first character you want to stop at, then return the one before it.)
Or you can use a regex to match what you want to keep, then take the last match. (Or use a regex replace to remove what you don't want to keep, then take the last character.)
Naive:
<?php
$s = "Some text.....!!!!!!!!?????";
$ary = str_split($s);
$position = 0;
$last = 0;
foreach ($ary as $char) {
if (preg_match("/[a-zA-Z0-9]/", $char)) {
$last = $position;
}
$position += 1;
}
echo $last;
?>
<?php
$str = '"Some text.....!!!!!!!!?????"';
$last = -1;
foreach(range('a', 'z') as $letter)
{
$last = max($last, strripos($str, $letter));
}
echo "$last\n"; // 9
?>
Here is a simple and straight-forward O(n) algorithm.
From the manual for ctype_alpha():
In the standard C locale letters are
just [A-Za-z]
If you need a different locale, you should abstract the function that determines if a character is alpha or not. That way you can keep this algorithm and adapt to varying languages.
function lastAlphaPosition($string) {
$lastIndex = strlen($string)-1;
for ($i = $lastIndex; $i > 0; --$i) {
if (ctype_alpha($string[$i])) {
return $i;
}
}
return -1;
}
$testString = 'Some text.....!!!!!!!!?????';
$lastAlphaPos = lastAlphaPosition($testString);
if ($lastAlphaPos !== -1) {
echo $testString[$lastAlphaPos];
} else {
echo 'No alpha characters found.';
}