Need to hep to change multiple characters in a string using some loop without built-in functions in PHP.
<?php
$givenString = "School";
$i=0;
while($givenString[$i]){
$i++;
if($givenString[$i] == o){
$givenString[$i] = 0;
}
}
echo $givenString;
?>
Result: Sch0ol
Required Result: Sch00l
Because your loop logic is out of order. Feed in the string "ooooo" and you'll get "o0ooo" out. It skips the first letter because the first thing you do is move the index ahead, and it stops after the first replacement because you're testing the character that you just replaced, and "0" type-juggles to boolean as false.
Move $i++ to the end of the loop and you'll get "00000", but also Warning: Uninitialized string offset 6. This is because you're relying on the error to break the loop. You need to bound the loop on the length of the string, not the content.
So:
$givenString = "oooooo";
$i=0;
$c=strlen($givenString);
while($i<$c){
if($givenString[$i] == 'o'){
$givenString[$i] = 0;
}
$i++;
}
echo $givenString;
or we can condense that with for loop:
$givenString = "oooooo";
for( $i=0, $c=strlen($givenString); $i<$c; $i++ ){
if($givenString[$i] == 'o'){
$givenString[$i] = 0;
}
}
echo $givenString;
For completeness, the un-quoted o in your post only works because pre-8.0 PHP assumed that unquoted constants were just "oopsies" meant to be strings and replaced them with their string equivalent, issuing a Notice like Notice: Use of undefined constant o - assumed 'o', which can potentially have serious side-effects.
This error also indicates that you're using a version of PHP that is no longer supported, and you should ensure that you are writing code on a supported version.
In your current code, you are replacing all o to 0 which is off-track with respect to replacing oo to 00 and also skipping the current o at hand doesn't make sense. Also, as already pointed out, matching a string with a string is better than comparing with just o directly.
You can instead match o with o and check if string contained a previous o or not. If it did, mark both previous and current location as 0, or else, leave it as is. Since you didn't wish to use inbuilt functions, you can use null-coalescing operator(??) to check with the length of the string as well.
<?php
function modify($string){
for($i = 1; ($string[$i] ?? false) !== false; ++$i){
if($string[ $i ] === 'o' && $string[$i - 1] === 'o'){
$string[ $i ] = $string[$i - 1] = '0';
}
}
return $string;
}
Online Demo
Related
The goal is to get from string $a="NewYork" new string without lowercase that stands before uppercase.
In this example, we should get output "NeYork"
I tried to do this through positions of small and big letters in ASCII table, but it doesn't work. I'm not sure is it possible to to do this in similar way, through positions in ASCII table.
function delete_char($a)
{
global $b;
$a = 'NewYork';
for($i =0; $i<strlen($a); $i++)
{
if( ord($a[$i])< ord($a[$i+1])){//this solves only part of a problem
chop($a,'$a[$i]');
}
else{
$b.=$a[$i];
}
}
return $b;
}
This is something a regular expression handles with ease
<?php
$a ="NewYorkNewYork";
$reg="/[a-z]([A-Z])/";
echo preg_replace($reg, "$1", $a); // NeYorNeYork
The regular expression searches for a lower case letter followed by an upper case letter, and captures the upper case one. preg_replace() then replace that combination with just the captured letter ($1).
See https://3v4l.org/o43bO
You don't need to capture the uppercase letter and use a backreference in the replacement string.
More simply, match the lowercase letter then use a lookahead for an uppercase letter -- this way you only replace the lowercase character with an empty string. (Demo)
echo preg_replace('~[a-z](?=[A-Z])~', '', 'NewYork');
// NeYork
As for a review of your code, there are multiple issues.
global $b doesn't make sense to me. You need the variable to be instantiated as an empty string within the scope of the custom function only. It more simply should be $b = '';.
The variable and function naming is unhelpful. A function's name should specifically describe the function's action. A variable should intuitively describe the data that it contains. Generally speaking, don't sacrifice clarity for brevity.
As a matter of best practice, you should not repeatedly call a function when you know that the value has not changed. Calling strlen() on each iteration of the loop is not beneficial. Declare $length = strlen($input) and use $length over and over.
$a[$i+1] is going to generate an undefined offset warning on the last iteration of the loop because there cannot possibly be a character at that offset when you already know the length of the string has been fully processed. In other words, the last character of a string will have an offset of "length - 1". There is more than one way to address this, but I'll use the null coalescing operator to set a fallback character that will not qualify the previous letter for removal.
Most importantly, you cannot just check that the current ord value is less than the next ord value. See here that lowercase letters have an ordinal range of 97 through 122 and uppercase letters have an ordinal range of 65 through 90. You will need to check that both letters meet the qualifying criteria for the current letter to be included in the result string.
Rewrite: (Demo)
function removeLowerCharBeforeUpperChar(string $input): string
{
$output = '';
$length = strlen($input);
for ($offset = 0; $offset < $length; ++$offset) {
$currentOrd = ord($input[$offset]);
$nextOrd = ord($input[$offset + 1] ?? '_');
if ($currentOrd < 97
|| $currentOrd > 122
|| $nextOrd < 65
|| $nextOrd > 90
){
$output .= $input[$offset];
}
}
return $output;
}
echo removeLowerCharBeforeUpperChar('MickMacKusa');
// MicMaKusa
Or with ctype_ functions: (Demo)
function removeLowerCharBeforeUpperChar(string $input): string
{
$output = '';
$length = strlen($input);
for ($offset = 0; $offset < $length; ++$offset) {
$nextLetter = $input[$offset + 1] ?? '';
if (ctype_lower($input[$offset]) && ctype_upper($nextLetter)) {
$output .= $nextLetter; // omit current letter, save next
++$offset; // double iterate
} else {
$output .= $input[$offset]; // save current letter
}
}
return $output;
}
To clarify, I would not use the above custom function in a professional script and both snippets are not built to process strings containing multibyte characters.
Simply, I create new variable $s used for store new string to be returned and a make loop iterate over $a string, I used ctype_upper to check if next character not uppercase append it to $s. at the end i return $s concatenate with last char of string.
function delete_char(string $a): string
{
if(!strlen($a))
{
return '';
}
$s='';
for($i = 0; $i < strlen($a)-1; $i++)
{
if(!ctype_upper($a[$i+1])){
$s.=$a[$i];
}
}
return $s.$a[-1];
}
echo delete_char("NewYork");//NeYork
Something like this maybe?
<?php
$word = 'NewYork';
preg_match('/.[A-Z].*/', $word, $match);
if($match){
$rlen = strlen($match[0]); //length from character before capital letter
$start = strlen($word)-$rlen; //first lower case before the capital
$edited_word = substr_replace($word, '', $start, 1); //removes character
echo $edited_word; //prints NeYork
}
?>
This question already has answers here:
Adding 2 to a variable each time
(5 answers)
Closed 1 year ago.
So I'm trying to make it so the computer counts up to ten by two and making a new line each time. When I tested this my entire computer crashed. What's wrong with it?
<?php
$test = 0;
while ($test < 10) {
$test + 2;
echo $test . "/n";
}
?>
Change:
$test + 2;
to:
$test += 2;
Currently, $test is always 0 in your code, since you are not assigning a new value to it, hence the infinite loop.
Additionally, you would also want to change:
echo $test . "/n";
to:
echo $test . "\n";
Since you need to use a backslash to indicate a new line character.
N.B. In PHP you can also use the PHP_EOL constant to indicate the end of a line.
Here you just sum $test with 2 but did not assign it back to $test
$test + 2;
Trying replace it by $test += 2;
Another point is /n is not "making a new line" as you expected, change it to \n instead.
Although you can use while statement, this is a good case to use for instead.
for($i=0; $i < 10; $i += 2)
{
echo $i . PHP_EOL;
}
Usually while is used to evaluate something every loop, some variable that can change inside the while, like a bool variable or an "infinite" loop until break.
When you have a already defined number of loops, for is usually a better approach.
I have an array of values that represent points on a line chart:
$temperatures = [23, 24, null, '', 25, '', '', null];
I'm using PHP4, but I think it can be answered in any language.
Array contains only numbers, nulls and empty strings.
Numbers represent temperatures, nulls mean that the instruments weren't working and empty strings represent neither (instruments are working, just not measuring anything).
Points must (in most cases) be connected, since it's a line chart.
I have a variable $gap that corresponds to each point and tells whether this point is connected to the next point. If it is set to true, than the points are not connected (false otherwise). For example, $gap for temperatures[0] must be set to false, since the line is drawn between temperatures[0] and temperatures[1](they are both valid temperatures). $gap fortemperatures[1]andtemperatures[2]` must be true, since there is null following. And so on.
When there is null the $gap is absolutely true. For numbers and empty strings, it depends on: if a null follows, gap is true; if a number follows, gap is false. If empty string follows, we must check if afterwards comes null or number and apply the previous sentence accordingly. If there are just empty strings following, gap is true. Here is my code that is working too slow, but produce correct results:
$limit = count($temperatures);
for ($i = 0; $i <= limit; $i++) {
$next_is_number = false;
if (is_null($temperatures[i]) {
$gap = true;
} else {
for ($y = $i + 1; $i <= limit; $i++) {
if (is_null($temperatures[$y]) {
break;
} elsif (is_numeric($temperatures[$y]) {
$next_is_number = true;
break;
}
}
if ($next_is_number) {
$gap = false;
} else {
$gap = true;
}
}
}
How can I speed it up?
Your code checks whether there is a a gap somewhere in your line chart or not.
So once a gap is found, there no reason to continue in the outer for-loop. Think of a chart of 1000 values, if there is a gap between the first two values it makes no sense to continue checking the other 998 values.
Thus, the first thing I would recommend is to set $gap = false at the beginning and to leave the loop once $gap is true. You could do that either with
1.) break (not so elegant),
2.) extract your code to a method and add a return-statement or
3.) adding a condition in the for-loop. I am not familiar with php but in most languages it is possible to do it like this:
$gap = false;
$limit = count($temperatures);
for ($i = 0; $i <= limit && !$gap; $i++) {
[...]
So once $gap is true, the outer for-loop is left.
Iterate through backwards, remembering the last valid value and putting that in when you see an empty string. Then it's O(n) worst case, not O(n^2).
Alternatively, you can work from $y - 1 to $x (or vice versa) after the inner loop, setting the values of your gaps array / outputting values, then skip past all the ones you've just done ($x = $y). This is also O(n).
Then, once you've got the algorithm as fast as you can, you can ditch PHP and write it in something like Rust or C. (I don't recall any true arrays in the language, so they're always going to be slow.)
<?php
$a = "Hello World I am Neha Singh Chouhan";
$length = 0;
do {
$length++;
}
while ($a[$length] != null);
echo "Length = ".$length."<br/>";
for ($i = $length - 1; $i >= 0; $i--) {
echo $a[$i];
}
?>
tried to calculate the string length without using inbuilt function strlen().
the output was
Notice: Uninitialized string offset: 35 in C:\xampp\htdocs\Neha\ProgramsFromClass\10_reverse_string.php on line 7
Length = 35
nahuohC hgniS aheN ma I dlroW olleH
What causes the notice and how can i get rid of it?
Your loop is incorrect. You increment your $length BEFORE you start using it, and run off the end of the string. Therefore you're testing offsets, 1,2,3,...n, where n is one past the end of the string.
And since you're testing for a non-existent "array" key, no matter how you look at it, you'll always get the error, even after you swap the loop types.
do/while is NOT the loop to use for this. You want a plain while loop, and use isset() instead:
$length = 0;
while(isset($a[$length])) { $length++; }
See the following code snippet
$i=1;
echo $i.($i++);
in a quick, I thought the result would be 12 but the actual result is 21.
also
echo $i,$i++;
I thought it would be 12 but its 11 .
echo ($i = ($i++)); //result is 1
echo ($i = ($i+1)); //result is 2
But why?
When a variable is not involved into any arithmetic operation (like your first $i), PHP will not create a temporary variable.
Thus, your first $i will be evaluated at the end of the statement, when $i++ has already been executed.
To prevent this, you can still write:
echo ($i += 0).($i++);
But this is obviously not a good coding practice.
EDIT: When you use , it is actually syntactic sugar to shorten two PHP statements. It is strictly equivalent to:
echo $i;
echo $i++;
Since incrementation is executed after the last statement, 11 is indeed the result.
First example
Code in brackets is evaluated first - in this case ($i++). The value of $i is taken (1) and then the variable is incremented to 2. So you then have this, where $i is 2.
echo $i . '1'
From this, the value of $i is substituted in, and you get '2' . '1', which is concatenated to give '21'.
Second example
It's easier to rewrite this to clear up the , separator. The line echo $i, $i++; is equivalent to:
echo $i;
echo $i++;
The first line obviously outputs 1, and the second will output that same value, then increment $i (++ is the post-increment operator). If you were to put another echo $i; at the end, it would output 2.
As per the PHP documentation stated at: Operator Precedence
First Case
$i=1;
echo $i.($i++);
$i is initialized to value 1. Now, ++ follows a higer precedence than . and it has right-associative. This means your $i++ will be evaluated first. In this case , the value of $i++ will be 1 and the next value of $i will get incremented to 2. hence $i is 2
Now . has the next precendence after ++, which is left-associative. hence it will evaluate values starting from left.
so $i=2 and $i++ =1, hence the output 21
Second Case
$i=1;
echo $i,$i++;
Here, there is only one operator ++. Hence the need for comparision of precedence doesn't arise. Hence, it will be evalauted by default standard of left-associative. $i = 1, $i++ = 1. Hence 11
Third Case
echo ($i = ($i++)); //result is 1
In this case, now = is an assignment operator and is right-associative, so $i++ = 1. And since it is an assignment operator value of $i++ will be stored in $i. hence echo ($i = 1); which will result in output being 1.
Fourth Case
echo ($i = ($i+1)); //result is 2
Again, this will be right-associative, so $i+1 = 2. hence echo ($i = 2); which will result in output being 2.
Firstly for the second place it uses $i eq 1
Then it increases it to 2;
So for the first place it uses 2 and for the second - 1