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/>';
Related
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'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
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
This question already has answers here:
How To Replace Some Characters With Asterisks
(5 answers)
Closed 9 years ago.
How to replace all characters of string to asterisks except first and last characters in PHP?
For example test should become t**t and profanity become p******y and so on
function get_starred($str) {
$len = strlen($str);
return substr($str, 0, 1).str_repeat('*', $len - 2).substr($str, $len - 1, 1);
}
$myStr = 'YourName';
echo get_starred($myStr); //should show Y******e
Here a small function:
function asterisks($toConvert) {
$astNumber = strlen($toConvert) - 2;
return substr($toConvert, 0, 1) . str_repeat("*", $astNumber) . substr($toConvert, -1);
}
$tempString= 'teststring';
echo asterisks($tempString);
$str = "test";
$len = strlen($str);
$str1 = '';
for($i=0; $i < $len; $i++) {
if($i != 0 && $i != ($len-1)) {
$str1 .= '*';
} else {
$str1 .= $str[$i];
}
}
echo $str1;
Use the above code. This will fulfill your requirement.
Something like
$split_string = str_split($start_string);
$i = 1;
while ( $i < count($split_string)-2 ){
split_string[$i] = '*';
$i++;
}
This will replace the first and last like *bcdefghijklm* characters from variable $text;
$text = 'abcdefghijklmn';
$count = strlen($text)-1;
echo str_replace(array($text[0], $text[$count]), '*', $text);
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