Uninitialized string offset: -1 when referencing single string character with curly braces - php

I have this code:
$len = strlen($string);
if ($string{$len-1} == '-') {
// Do stuff...
}
However I get the following NOTICE error:
Uninitialized string offset: -1
When I var_dump($len-1) the value I get:
int 3
When I var_dump($string) I get:
string 'bobo' (length=4)
So could anyone tell me why this is causing a NOTICE error?

To prevent notice add additional condition to if statement:
$len = strlen($string);
if ($len > 0 && $string{$len-1} == '-')
// Do stuff...
}
or use substr function:
if (substr($string, -1) == '-') {
// Do stuff...
}

$len = strlen($string);
if(isset($string{$len-1})){
if ($string{$len-1} == '-') {
// Do stuff...
}
}

Related

Uninitialized string offset php

I am writting my own calculator on PHP.
I have a problem with my code because i don't know where i am trying to read too far in the string. So if anyone can enlighten me ..
The exact error i get is :
PHP Notice: Uninitialized string offset: 4 in /home/salim/Bureau/web/piscine_php/d01/ex11/do_op_2.php on line 76
Here is the code below :
function decoupe ($argv)
{
global $nbr1;
global $nbr2;
global $sign;
$string = NULL;
$string = trim($argv[1], " \t");
echo $string;
echo "\n";
$x = 0;
while($string[$x])
{
if (is_numeric($string[0]) == false)
error_msg();
if (is_numeric($string[$x]) && $string[$x + 1])
{
while (is_numeric($string[$x]))
{
$nbr1 .= $string[$x];
$x++;
}
}
if (is_thisoperator(substr($string, $x)))
{
$sign .= $string[$x];
$x++;
}
else
{
error_msg();
}
if ($string[$x + 1] && is_numeric($string[$x]))
{
while (is_numeric($string[$x]))
{
$nbr2 .= $string[$x];
$x++;
}
}
else
{
error_msg();
}
}
Don't use $string[$x] as a way to test whether $x is a valid index in the string. It prints a warning when $x is outside the string. Use $x < strlen($string) instead. So change:
while ($string[$x])
to
while ($x < strlen($string))
and change
if ($string[$x + 1] && is_numeric($string[$x]))
to
if ($x + 1 < strlen($string) && is_numeric($string[$x]))

Unable to read blank spaces in string

What's wrong with this code. I want to read the number of blank spaces without using any built in function, but it wont return or read the blank spaces:
$string = "can you look into this??";
$i = 0;
$breakPoints = 0;
while ($string[$i] != '' & $string[$i + 1] != '') {
if ($string[$i] == "" || empty($string[$i])) {
die("cdsd");
$breakposition = $string[$i];
$breakPoints++;
} else {
print_r($string[$i]);
}
$i++;
}
echo($breakPoints);
It's always going into the else part and never goes into the if statement. I even tried using isset() but that also didn't work. Where am I making a mistake?
Just loop while the string offset isset() and check if it equals a space. No need to do anything with $i+1:
$string = "can you look into this??";
$i = 0;
$breakPoints = 0;
while (isset($string[$i])) {
if ($string[$i] == " ") {
$breakposition = $string[$i];
$breakPoints++;
} else {
print_r($string[$i]);
}
$i++;
}
echo($breakPoints);
This outputs:
canyoulookintothis??4
Once you've got your code right, you will always run into an string index error and you will need the isset() built in function to check before performing operations.
In other words, the i for the index will eventually point beyond the last letter of the string, this will cause a PHP error. You can use isset() to check for it and break out of the loop. Example:
$string = "can you look into this??";
$i = 0;
$breakPoints = 0;
while (isset($string[$i])) {
if ($string[$i] == " ") {
$breakPoints++;
} else {
if($string[$i] != ''){
print_r($string[$i]);
}
}
$i++;
}
echo("<br />Number of spaces: ".$breakPoints
spaces is not empty, it will tack size.
so use this
$string = "can you look into this??";
$i = 0;
$breakPoints = 0;
while ($string[$i] != '' & $string[$i + 1] != '') {
if ($string[$i] == " ") {
echo " ";
$breakposition = $string[$i];
$breakPoints++;
} else {
print_r($string[$i]);
}
$i++;
}
echo($breakPoints);
DEMO
or try this code,
use preg_match_all.
$matches = " ";
$numSpaces = preg_match_all('/[ ]/', $string , $matches);
or Use this::
substr_count($string , ' ');

Uninitialized string offset error in simple for loop php

my goal is to convert every space " " in string to "%".
Here is my function:
<?php
$nazov = "dasa sdas da sd";
$buttonNazov = "";
for($i=0;$i<=strlen($nazov);$i++) {
if($nazov[$i] === " ") {
$buttonNazov .= "%"; // Line# 6
} else {
$buttonNazov .= $nazov[$i]; // Line#12
}
}
echo $buttonNazov;
?>
I am getting output but also 2 errors:
( ! ) Notice: Uninitialized string offset: 15 in C:\wamp\www\test.php on line 6
( ! ) Notice: Uninitialized string offset: 15 in C:\wamp\www\test.php on line 12
dasa%sdas%da%sd
from Mark Baker comment: Offset begins at 0, not at 1; so $i<strlen($nazov) and not $i<=strlen($nazov)
below is more better way of writing same
<?php
$nazov = "dasa sdas da sd";
$buttonNazov = "";
$len = strlen($nazov);
for($i=0; $i<$len; $i++) {
if("" === $nazov[$i]) {
$buttonNazov .= "%";
} else {
$buttonNazov .= $nazov[$i];
}
}
echo $buttonNazov;
?>
alternative way if you want to replace space with %
$buttonNazov = str_replace(' ', '%', $nazov);
the last index of a string $nazov is $nazov[strlen($nazov)-1], so use < instead of <= in the loop condition:
for($i=0;$i<strlen($nazov);$i++)

Notice: Uninitialized string offset: 62 in /.../libraries/functions.php on line 316

Man oh man I cannot figure this out... Please help.
What a missing here?
here are the errors:
Notice: Uninitialized string offset: 62 in /..../libraries/functions.php on line 316
Notice: Undefined variable: stilldo in /..../libraries/functions.php on line 322
Here is the code:
function generate_password($length = 12, $letters = true, $mixed_case = true, $numbers = true, $punctuation = false){
## Generate the alfa
$alfa = '';
if($letters == true) $alfa .= 'abcdefghijklmnopqrstuvwxyz';
if($mixed_case == true) $alfa .= strtoupper('abcdefghijklmnopqrstuvwxyz');
if($numbers == true) $alfa .= '0123456789';
if($punctuation == true)$alfa .= '~!##$%^&*(),.=+<>';
## Set Random Seed
if(!function_exists('_generate_password_seed')):
function _generate_password_seed(){
list($usec, $sec) = explode(' ', microtime());
return (float) $sec + ((float) $usec * 100000);
}
endif;
srand(_generate_password_seed());
## Generate the password
$token = "";
for($i = 0; $i < $length; $i ++) {
$token .= $alfa[#rand(0, #strlen($alfa))];
}
## Check the length
if(strlen($token) < $length){
// echo $stilldo = $length - strlen($token);
$token .= generate_password($stilldo);
}
## Return the password
return $token;
}
I get this error 5 out of 10 times i run this function and I can't seem to crack it.
Notice: Undefined variable: stilldo means, that a variable $stilldo is not defined, nor initialized... That means, that You call function generate_password in recursion when passing it an undefined variable, that in fact has a null value. Therefore Your function cannot work properly.
The part of your code should look like this:
## Check the length
if(strlen($token) < $length){
$stilldo = $length - strlen($token);
$token .= generate_password($stilldo);
}
Yes, a stupid mistake - You commented out the right line (where only echo should be commented out or deleted).
Enjoy!

Fast case counting

I have a large number of strings to process in php. I want to "fix" them to be title case (using ucwords(strtolower($str))) but only if they are all upper or all lower case already. If they are already mixed case, I'd just rather just leave them as they are.
What is the fastest way to check for this? It seems like foring through the string would be a rather slow way to go about it.
Here's what I have, which I think will be too slow:
function fixCase($str)
{
$uc = 0;
$lc = 0;
for($i=0;$i<strlen($str);$i++)
{
if ($str[$i] >= 'a' && $str[$i] <= 'z')
$lc++;
else if ($str[$i] >= 'A' && $str[$i] <= 'Z')
$uc++;
}
if ($uc == 0 || $lc == 0)
{
return ucwords(strtolower($str));
}
}
just use a string compare (case sensitive)
function fixCase($str)
{
if (
(strcmp($str, strtolower($str)) === 0) ||
(strcmp($str, strtoupper($str)) === 0) )
{
$str = ucwords(strtolower($str));
}
return $str;
}
There's not going to be any amazing optimization, because by the nature of the problem you need to look at every character.
Personally, I would just loop over the characters of the string with this sort of algorithm:
Look at the first character in the string, set a variable indicating whether it was upper or lowercase.
Now examine each character sequentially. If you get to the end of the string and they've all been the same case as the first character, fix the string's case as you like.
If any character is a different case than the first character was, break the loop and return the string.
Edit: actual code, I think this is about as good as you're going to get.
// returns 0 if non-alphabetic char, 1 if uppercase, 2 if lowercase
function getCharType($char)
{
if ($char >= 'A' && $char <= 'Z')
{
return 1;
}
else if ($char >= 'a' && $char <= 'z')
{
return 2;
}
else
{
return 0;
}
}
function fixCase($str)
{
for ($i = 0; $i < strlen($str); $i++)
{
$charType = getCharType($str[$i]);
if ($charType != 0)
{
$firstCharType = $charType;
break;
}
}
for ($i = $i + 1; $i < strlen($str); $i++)
{
$charType = getCharType($str[$i]);
if ($charType != $firstCharType && $charType != 0)
{
return $str;
}
}
if ($firstCharType == 1) // uppercase, need to convert to lower first
{
return ucwords(strtolower($str));
}
else if ($firstCharType == 2) // lowercase, can just ucwords() it
{
return ucwords($str);
}
else // there were no letters at all in the string, just return it
{
return $str;
}
}
You could try the string case test function I posted here
function getStringCase($subject)
{
if (!empty($subject))
{
if (preg_match('/^[^A-Za-z]+$/', $subject))
return 0; // no alphabetic characters
else if (preg_match('/^[^A-Z]+$/', $subject))
return 1; // lowercase
else if (preg_match('/^[^a-z]+$/', $subject))
return 2; // uppercase
else
return 3; // mixed-case
}
else
{
return 0; // empty
}
}
If the reason you want to avoid fixing already mixed-case strings is for efficiency then you are likely wasting your time, convert every string no matter its current condition:
function fixCase($str)
{
return ucwords(strtolower($str));
}
I would be very surprised if it ran any slower than the accepted answer for strings the length of those you would generally want to title case, and it's one less condition you need to worry about.
If, however, there is good reason to avoid converting already mixed-case strings, for example you want to preserve some intended meaning in the casing, then yes, jcinacio's answer is certainly the simplest and very efficient.
Wouldn't it be easier to check if the string = lowercase(string) or string = uppercase(string) and if so then leave it. Otherwise perform your operation.
Well I decided to do a test of the 2 proposed answers thus far and my original solution. I wouldn't have thought the results would turn out this way, but I guess native methods are /that/ much faster over all.
Code:
function method1($str)
{
if (strcmp($str, strtolower($str)) == 0)
{
return ucwords($str);
}
else if (strcmp($str, strtoupper($str)) == 0)
{
return ucwords(strtolower($str));
}
else
{
return $str;
}
}
// returns 0 if non-alphabetic char, 1 if uppercase, 2 if lowercase
function getCharType($char)
{
if ($char >= 'A' && $char <= 'Z')
{
return 1;
}
else if ($char >= 'a' && $char <= 'z')
{
return 2;
}
else
{
return 0;
}
}
function method2($str)
{
for ($i = 0; $i < strlen($str); $i++)
{
$charType = getCharType($str[$i]);
if ($charType != 0)
{
$firstCharType = $charType;
break;
}
}
for ($i = $i + 1; $i < strlen($str); $i++)
{
$charType = getCharType($str[$i]);
if ($charType != $firstCharType && $charType != 0)
{
return $str;
}
}
if ($firstCharType == 1) // uppercase, need to convert to lower first
{
return ucwords(strtolower($str));
}
else if ($firstCharType == 2) // lowercase, can just ucwords() it
{
return ucwords($str);
}
else // there were no letters at all in the string, just return it
{
return $str;
}
}
function method0($str)
{
$uc = 0;
$lc = 0;
for($i=0;$i<strlen($str);$i++)
{
if ($str[$i] >= 'a' && $str[$i] <= 'z')
$lc++;
else if ($str[$i] >= 'A' && $str[$i] <= 'Z')
$uc++;
}
if ($uc == 0 || $lc == 0)
{
return ucwords(strtolower($str));
}
}
function test($func,$s)
{
$start = gettimeofday(true);
for($i = 0; $i < 1000000; $i++)
{
$s4 = $func($s);
}
$end = gettimeofday(true);
echo "$func Time: " . ($end-$start) . " - Avg: ".sprintf("%.09f",(($end-$start)/1000000))."\n";
}
$s1 = "first String";
$s2 = "second string";
$s3 = "THIRD STRING";
test("method0",$s1);
test("method0",$s2);
test("method0",$s3);
test("method1",$s1);
test("method1",$s2);
test("method1",$s3);
test("method2",$s1);
test("method2",$s2);
test("method2",$s3);
Results:
method0 Time: 19.2899270058 - Avg: 0.000019290
method0 Time: 20.8679389954 - Avg: 0.000020868
method0 Time: 24.8917310238 - Avg: 0.00002489
method1 Time: 3.07466816902 - Avg: 0.000003075
method1 Time: 2.52559089661 - Avg: 0.000002526
method1 Time: 4.06261897087 - Avg: 0.000004063
method2 Time: 19.2718701363 - Avg: 0.000019272
method2 Time: 35.2485661507 - Avg: 0.000035249
method2 Time: 29.3357679844 - Avg: 0.000029336
Note that anything that looks only at [A-Z] will be incorrect as soon as there are accented or umlaut characters. Optimizing for speed is meaningless if the result is incorrect (hey, if the result doesn't have to be correct, it can write you a REALLY fast implementation...)

Categories