string manipulation uppercase and lowercase in PHP - php

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

Related

replace string php, but every change make a new variabel

i have
$str ="GOODDAY"
and i need to replace O with U , but not change ALL O characters.
For example
$str1 ="GUODDAY" ;
$str2 ="GOUDDAY" ;
$str3 ="GUUDDAY" ;
i used str_replace but only get $str3 , any idea?
It looks like you want to print the string as many times as the occurrences of O, and replace O once each time, according to the iteration number, and finally print the string with all O replaced. This will do it:
$str = "GOODDAY";
$find = "O";
$replaceWith = "U";
$lastPos = 0;
while (($lastPos = strpos($str, $find, $lastPos)) !== false) {
echo substr_replace($str, $replaceWith, $lastPos, 1) . "\n";
$lastPos = $lastPos + strlen($find);
}
echo str_replace($find, $replaceWith, $str);
https://3v4l.org/ddg73
Maybe something like this :
$str ="GOODDAY";
for ($i = 0; $i < strlen($str); $i++) {
if ($str[$i] === 'O' && rand(0, 1) === 1) {
$str[$i] = 'U';
}
}
echo $str;
Edit :
If you want at least 1 U with same chances for each possibility:
do {
$str ="GOODDAY";
$good = false;
for ($i = 0; $i < strlen($str); $i++) {
if ($str[$i] === 'O' && rand(0, 1) === 1) {
$str[$i] = 'U';
$good = true;
}
}
} while (false === $good);
echo $str;

How to capitalize first letter of word in php without ucfirst() function

I am trying to capitalize the first letter of word in php without using ucfirst() function But i am not able do it , but i am struggling with this. Please tell me its answer.
<?php
$str ="the resources of earth make life possible on it";
$str[0] = chr(ord($str[0])-32);
$length = strlen($str);
for($pos=0; $pos<$length; $pos++){
if($str[$pos]==' '){
$str[$pos+1] = chr(ord($str[$pos+1])-32);
}
}
echo $str;
?>
Without using the function ucfirst, you can do it like this:
$firstLetter = substr($word, 0, 1);
$restOfWord = substr($word, 1);
$firstLetter = strtoupper($firstLetter);
$restOfWord = strtolower($restOfWord);
print "{$firstLetter}{$restOfWord}\n";
To do it for each word, use explode(' ', $string) to get an array of words, or preg_split('#\\s+#', $string, -1, PREG_SPLIT_NO_EMPTY) for better results.
I would advise against just subtracting 32 from the first character of the next word:
you do not know it is a letter
you do not know it isn't already capitalized
you do not know it exists
you do not know it is not another space
At the very least check that its ord() value lies between ord('A') and ord('Z').
To do this all without case-changing functions, you'd do
$text = implode(' ',
array_map(
function($word) {
$firstLetter = substr($word, 0, 1);
if ($firstLetter >= 'a' && $firstLetter <= 'z') {
$firstLetter = chr(ord($firstLetter)-32);
}
$restOfWord = substr($word, 1);
$len = strlen($restOfWord);
for ($i = 0; $i < $len; $i++) {
if ($restOfWord[$i] >= 'A' && $restOfWord[$i] <= 'Z') {
$restOfWord[$i] = chr(ord(restOfWord[$i])+32);
}
}
return $firstLetter . $restOfWord;
},
preg_split('#\\s+#', $originalText, -1, PREG_SPLIT_NO_EMPTY)
)
);
as such...
$str ="the resources of earth make life possible on it";
$words=array_map(static fn($a) => ucfirst($a), explode(' ', $str));
echo implode(' ', $words);
with ord and chr
$ordb=ord('b'); //98
$capitalB=chr(98-32); //B
$ordA=ord('a'); //97
$caiptalA=chr(97-32); //A
//so
function capitalize(string $word)
{
$newWord = '';
$previousCharIsEmpty = true;
$length = strlen($word);
for ($a = 0; $a < $length; $a++) {
if ($word[$a] === ' ') {
$newWord .= ' ';
$previousCharIsEmpty = true;
} else {
if ($previousCharIsEmpty === true) {
$ord = ord($word[$a]);
$char = chr($ord - 32);
$newWord .= $char;
$previousCharIsEmpty = false;
} else {
$newWord .= $word[$a];
}
$previousCharIsEmpty = false;
}
return $newWord;
}
$word = 'this for example by dilo abininyeri';
echo capitalize($word);
and output
This For Example By Dilo Abininyeri
We cannot do this without any function. We have to use some function. Like you have applied the for-loop and for strlen function.
<?php
$str ="the resources of earth make life possible on it";
$str[0] = chr(ord($str[0])-32);
$length = strlen($str);
for($pos=0; $pos<$length; $pos++){
if($str[$pos]==' '){
$str[$pos+1] = chr(ord($str[$pos+1])-32);
}
}
echo $str;
?>

Split a string into two equal length parts using PHP [duplicate]

This question already has answers here:
How to split a long string without breaking words?
(4 answers)
Closed 1 year ago.
I need to split a string into two equal length parts.String can contain blank spaces, commas or anything. I have referred and tries the code sample of explode statement from the link http://www.testingbrain.com/php-tutorial/php-explode-split-a-string-by-string-into-array.html but there it not showing any sample for splitting by equal length.
One more thing, while splitting words shouldn't broken.
This will split without breaking the word, at the most possible half of the text, but it may split at any other characters (,,.,# etc)
$data = "Split a string by length without breaking word"; //string
if (strlen($data) % 2 == 0) //if lenhth is odd number
$length = strlen($data) / 2;
else
$length = (strlen($data) + 1) / 2; //adjust length
for ($i = $length, $j = $length; $i > 0; $i--, $j++) //check towards forward and backward for non-alphabet
{
if (!ctype_alpha($data[$i - 1])) //forward
{
$point = $i; //break point
break;
} else if (!ctype_alpha($data[$j - 1])) //backward
{
$point = $j; //break point
break;
}
}
$string1 = substr($data, 0, $point);
$string2 = substr($data, $point);
here you go.
$str="Test string";
$middle=strlen($str)/2;
$first=substr($str,0,$middle);
$last=substr($str,$middle);
I think this is are good start:
$string = "My name is StackOcerflow and I like programming, one more comma. Next sentance.";
$words = preg_split( "/( )/", $string );
print_r($words);
$length = 0;
foreach($words as $word){
$length += strlen($word);
}
$string_new = "";
$string_new2 = "";
$length_half = 0;
foreach($words as $word){
$length_half += strlen($word);
if($length_half >= ($length/2)){
$string_new2 .= $word . ' ';
}else{
$string_new .= $word . ' ';
}
}
echo '<br/><br/>';
echo 'Full=' . $string . '<br/>';
echo 'First=' . $string_new . '<br/>';
echo 'Second=' . $string_new2 . '<br/>';
echo 'First length=' . strlen($string_new) . '<br/>';
echo 'Second=' . strlen($string_new2) . '<br/>';

delete the repetetion letters in a string php

I'm trying to parse a string and delete the adjacent letters that are same. I want to return the count of number of deletions and output the resulted string after the deletions are made. Say I have
$str = "aaabbbcc";
As you can see, you need to do 5 deletions to make the adjacent letters not same. The $output string is "abc" and the number of deletions is five.
function str_deletions ($str)
{
$prev = $str[0];
$length = strlen($str);
$deletions = 0;
$output = "";
for ($i=1 ; $i < $length; $i++)
{
if ($str[$i]== $prev)
{
$deletions++;
$prev = $str[$i]; // not sure here ?
}
}
echo $output; // ?
return $deletions;
}
$str = "aabbcc";
echo str_deletions ($str);
EDIT
This is an interview question, I'm not supposed to use any built-in functions like regex or array_count_values
Thanks for your help !
Here is another regex solution. I use a regex to only match a word character that is repeated, and then remove each consecutive repeating character one by one, which allows me to use &$count argument with preg_replace:
count
If specified, this variable will be filled with the number of replacements done.
The regex is
(\w)(?=\1)
See demo. Note you can replace \w with . to match any character but a newline. OR if you need to match only letters, I suggest using '/(\p{L})(?=\1)/u'
See IDEONE demo:
$str = "aaabbbcc";
$cnt = -1;
$result = preg_replace('/(\w)(?=\1)/', "", $str, -1, $cnt);
echo "Result: " . $result . PHP_EOL . "Deletions: " . $cnt;
Output:
Result: abc
Deletions: 5
Regex solution
This is a much simpler way of doing what you're after using preg_replace():
<?php
function str_deletions($str){
$replaced = preg_replace("/(.)\\1+/", "", $str);
$length = strlen($str) - strlen($replaced);
return array("new_word" => $replaced, "chars_replaced" => $length);
}
$str = "aabbcc";
$string_deletions = str_deletions($str);
echo "New String: " . $string_deletions['new_word'] . "\n";
echo "Chars deleted: " . $string_deletions['chars_replaced'] . "\n";
?>
No inbuilt functions
For the purposes of completion (and since you updated your question with more information to say that we can't use regexes because it's an interview question), here's what I'd do:
Using count_chars():
function str_deletions($str){
$string_data['new_word'] = count_chars($str,3);
$string_data['chars_replaced'] = strlen($str) - strlen($string_data['new_word']);
return $string_data;
}
$str = "aabbcc";
echo str_deletions($str);
Note: in this example count_chars(); will return unique chars in a string, not quite remove duplicates (i.e. "aabbccaa" would still yield "abc" as an output) but your question wasn't clear what the interviewer wanted - whether it was truly a remove duplicate question or a unique char question.
Using array_unique():
Slightly slower and a bit more heavy handed:
function str_deletions($str){
$string_array = array_unique(str_split($str));
foreach($string_array as $string_cur){
$string_data['new_word'] .= $string_cur;
}
$string_data['chars_replaced'] = strlen($str) - strlen($string_data['new_word']);
return $string_data;
}
$str = "aabbcc";
echo str_deletions($str);
Note: It's worth pointing out that if I realised it was an interview question, I wouldn't have provided an answer as doing it for you kind of defeats the purpose. Still, with the amount of answers here now and the fact that I've seen something similar to this in an interview, my hope is someone will learn from these.
The basic algorithm (indeed $prev = $str[$i]; isn't at the good place but you wasn't far):
function str_deletion($str) {
$del = 0;
if (1 < $length = strlen($str)) { // $str has more than 1 char
$prev = $str[0];
$output = $prev;
for ($i=1; $i<$length; $i++) {
if ($prev == $str[$i]) {
$del++;
} else {
$prev = $str[$i]; // when different, change the previous character
$output .= $prev; // and append it to the output
}
}
} else {
$output = $str;
}
echo $output;
return $del;
}
I have changed your function
this is not returning both the output string and number of deletions
function str_deletions ($str)
{
$prev = NULL;
$deletions = 0;
$output = "";
$i=0;
while ($i < strlen($str))
{
if (substr($str,$i,1) == $prev)
{
$deletions++;
//$prev = substr($str,$i,1);/*remove this line, no need here as the same stmnt is there after ifelse*/
}else{
$output.=substr($str,$i,1);
}
$prev = substr($str,$i,1);
$i++;
}
$arr = array(
'output'=>$output,
'deletions'=>$deletions
);
return $arr;
}
$str = "aaabbcc";
print_r(str_deletions ($str));
output for above function call is
Array ( [output] => abc [deletions] => 4 )
Solved with no external function except count;
$str="aaavvvffccca";
$count = strlen($str);
for($i=0;$i<$count;$i++){
$array[]=$str[$i];
}
$del =0;
for($i=0;$i<$count;$i++){
$next=isset($array[$i+1])?$array[$i+1]:null;
if($array[$i]==$next)
{
$del++;
}
else
{
$newarray[]=$array[$i];
}
}
echo "Filter Text:". implode('',$newarray);
echo"Total Deleted:".$del;
The straight forward solution to find out the number of deletions can be
If there are N consecutive same characters delete N-1 out of those N characters.
function str_likes($str)
{
$length = strlen($str);
$del = 0;
for ($i=0 ; $i < $length ; $i++)
{
if ($str[$i] == $str[$i+1])
{
$del++;
}
}
return $del;
}
$str = "aabbccaaa";
echo str_likes($str); //4

Reverse letters in each word of a string without using native splitting or reversing functions [duplicate]

This question already has answers here:
Reverse the letters in each word of a string
(6 answers)
Closed 1 year ago.
This task has already been asked/answered, but I recently had a job interview that imposed some additional challenges to demonstrate my ability to manipulate strings.
Problem: How to reverse words in a string? You can use strpos(), strlen() and substr(), but not other very useful functions such as explode(), strrev(), etc.
Example:
$string = "I am a boy"
Answer:
I ma a yob
Below is my working coding attempt that took me 2 days [sigh], but there must be a more elegant and concise solution.
Intention:
1. get number of words
2. based on word count, grab each word and store into array
3. loop through array and output each word in reverse order
Code:
$str = "I am a boy";
echo reverse_word($str) . "\n";
function reverse_word($input) {
//first find how many words in the string based on whitespace
$num_ws = 0;
$p = 0;
while(strpos($input, " ", $p) !== false) {
$num_ws ++;
$p = strpos($input, ' ', $p) + 1;
}
echo "num ws is $num_ws\n";
//now start grabbing word and store into array
$p = 0;
for($i=0; $i<$num_ws + 1; $i++) {
$ws_index = strpos($input, " ", $p);
//if no more ws, grab the rest
if($ws_index === false) {
$word = substr($input, $p);
}
else {
$length = $ws_index - $p;
$word = substr($input, $p, $length);
}
$result[] = $word;
$p = $ws_index + 1; //move onto first char of next word
}
print_r($result);
//append reversed words
$str = '';
for($i=0; $i<count($result); $i++) {
$str .= reverse($result[$i]) . " ";
}
return $str;
}
function reverse($str) {
$a = 0;
$b = strlen($str)-1;
while($a < $b) {
swap($str, $a, $b);
$a ++;
$b --;
}
return $str;
}
function swap(&$str, $i1, $i2) {
$tmp = $str[$i1];
$str[$i1] = $str[$i2];
$str[$i2] = $tmp;
}
$string = "I am a boy";
$reversed = "";
$tmp = "";
for($i = 0; $i < strlen($string); $i++) {
if($string[$i] == " ") {
$reversed .= $tmp . " ";
$tmp = "";
continue;
}
$tmp = $string[$i] . $tmp;
}
$reversed .= $tmp;
print $reversed . PHP_EOL;
>> I ma a yob
Whoops! Mis-read the question. Here you go (Note that this will split on all non-letter boundaries, not just space. If you want a character not to be split upon, just add it to $wordChars):
function revWords($string) {
//We need to find word boundries
$wordChars = 'abcdefghijklmnopqrstuvwxyz';
$buffer = '';
$return = '';
$len = strlen($string);
$i = 0;
while ($i < $len) {
$chr = $string[$i];
if (($chr & 0xC0) == 0xC0) {
//UTF8 Characer!
if (($chr & 0xF0) == 0xF0) {
//4 Byte Sequence
$chr .= substr($string, $i + 1, 3);
$i += 3;
} elseif (($chr & 0xE0) == 0xE0) {
//3 Byte Sequence
$chr .= substr($string, $i + 1, 2);
$i += 2;
} else {
//2 Byte Sequence
$i++;
$chr .= $string[$i];
}
}
if (stripos($wordChars, $chr) !== false) {
$buffer = $chr . $buffer;
} else {
$return .= $buffer . $chr;
$buffer = '';
}
$i++;
}
return $return . $buffer;
}
Edit: Now it's a single function, and stores the buffer naively in reversed notation.
Edit2: Now handles UTF8 characters (just add "word" characters to the $wordChars string)...
My answer is to count the string length, split the letters into an array and then, loop it backwards. This is also a good way to check if a word is a palindrome. This can only be used for regular string and numbers.
preg_split can be changed to explode() as well.
/**
* Code snippet to reverse a string (LM)
*/
$words = array('one', 'only', 'apple', 'jobs');
foreach ($words as $d) {
$strlen = strlen($d);
$splits = preg_split('//', $d, -1, PREG_SPLIT_NO_EMPTY);
for ($i = $strlen; $i >= 0; $i=$i-1) {
#$reverse .= $splits[$i];
}
echo "Regular: {$d}".PHP_EOL;
echo "Reverse: {$reverse}".PHP_EOL;
echo "-----".PHP_EOL;
unset($reverse);
}
Without using any function.
$string = 'I am a boy';
$newString = '';
$temp = '';
$i = 0;
while(#$string[$i] != '')
{
if($string[$i] == ' ') {
$newString .= $temp . ' ';
$temp = '';
}
else {
$temp = $string[$i] . $temp;
}
$i++;
}
$newString .= $temp . ' ';
echo $newString;
Output: I ma a yob

Categories