Unexpected string length when using strlen in php - php

I am stuck with the issue as currently the result is quite unexpected. I am calculating a hashed keyword length and it is surely giving me an unexpected result.
echo strlen("$2a$08$MphfRBNtQMLuNro5HOtw3Ovu20cLgC0VKjt6w7zrKXfj1bv8tNnNa");
Output - 6
Let me know the reason for this and why it is outputting 6 as a result.
Codepad Link - http://codepad.org/pLARBx6F

You must use single quotes '. With the double quotes ("), due to the $ in your string, parts of it get interpreted as variables.
Generally, it's not a bad idea to get accustomed to using single quotes unless you specifically need doubles.
Look at the "variables" contained here. They would be $2a, $08, and $MphfRBNtQM......
The first two couldn't be variables as they start with a number, thus, the 6 characters. The third one indeed could be a proper variable, but since it isn't set, it's empty.

Use the below code to calculate the string length -
echo strlen('$2a$08$MphfRBNtQMLuNro5HOtw3Ovu20cLgC0VKjt6w7zrKXfj1bv8tNnNa');
You need to use single quotes, as at the third occurrence of the symbol $, a alphabet is starting after it and it get treated as a new variable. So before this third occurrence of $ only 6 character were there and you were getting string length as 6

Try following
<?php
echo strlen('$2a$08$MphfRBNtQMLuNro5HOtw3Ovu20cLgC0VKjt6w7zrKXfj1bv8tNnNa');
?>
If you change your string and remove rest of '$' signs except the first one, then this will work fine because by adding $ it gets a special meaning in PHP.

Related

Is there a way to delimit "ucwords()" in PHP such that the first char is not automatically uppercased?

PHP has the function ucwords(), which allows for custom delimiters. This works well, and will turn my test string into My Test String no problem.
Take the following example: I want to make a super awesome 2009 gamer tag.
$gamerTag = 'xxx_l33t_xxx'; // Not yet epic.
echo ucwords($gamerTag,"x"); // want it to return 'xXx_l33t_xXx'
I would have assumed strings would delimit case-sensitively and update the the second x in each case, ignoring the third, since at that point the middle one would no longer match our delimiter.
However, this actually returns XxX_l33t_xXx, since it will automatically uppercase the first letter in the string.
I know that there are other methods of doing this (strsplit() array loops and pregreplace with a reverse lookup come to mind), but my primary question becomes the following:
Is there a way to delimit ucwords() such that it does not automatically uppercase the first character of the string?
The internal behaviour is unfortunately that the first character of the string will always be converted to upper case, regardless of the delimiters you pass in.
Digging into the PHP source, this is the implementation of ucwords:
*r = toupper((unsigned char) *r);
for (r_end = r + Z_STRLEN_P(return_value) - 1; r < r_end; ) {
if (mask[(unsigned char)*r++]) {
*r = toupper((unsigned char) *r);
}
}
From https://github.com/php/php-src/blob/master/ext/standard/string.c#L2651
Here r is the return value, and mask is a char array of the delimiting characters. The first call to toupper (outside the of the loop) means that there's no way to prevent the first character being converted.
Because this is done, it means the second character is not converted, since it's now preceded by X, not x. The third character is handled "correctly".
This can actually cause some strange cascading behaviour, since the return value is being iterated over while it's being modified:
php > echo ucwords('aaa', 'A');
AAA
The initial string doesn't contain the delimiting character anywhere, but the result is completely upper-case.
As mentioned in a comment, there's an open PHP bug to reflect this behaviour in the documentation here: https://bugs.php.net/bug.php?id=78393

floatval causes the digits after the thousand sep ',' to be erased

floatval('19500.00');
returns 19500 ;
however
echo floatval('19,500.00');
returns 19 ;
this could've really given me a big problem it was good that I've noticed :D ... is there some reason for that behavior or it's just a bug ... should all values be number_formatted before ouput?
You put that value in single quotes, so it's not treated as a numerical value, but as a string.
Here's php.net's explanation what happens to strings with floatval (from http://php.net/manual/en/function.floatval.php):
Strings will most likely return 0 although this depends on the
leftmost characters of the string.
Meaning: The leftmost characters of the string in your case is 19 - that's a numerical value again, so the output is 19.
Decimal and thousands separator symbols are defined by current locale used in your script.
You can set default_locale in php.ini globally, or change locale in your script on the go: http://php.net/manual/en/function.setlocale.php
Different locales have different separators. To check, which is the current separator symbol, you can use localeconv function: http://us2.php.net/manual/en/function.localeconv.php
$test = localeconv();
echo $test['decimal_point'];
#.
echo $test['thousands_sep'];
#,
But actually no one can make this function work properly with all these commas and dots, so the only solution is to clean the input removing everything except "." and numbers by regexp or str_replace:
echo floatval(preg_replace("/[^0-9\.]/", "", '19,500.00'));
#19500
echo floatval(str_replace(",", "", '19,500.00'));
#19500

Regex match number consisting of specific range, and length?

I'm trying to match a number that may consist of [1-4], with a length of {1,1}.
I've tried multiple variations of the following, which won't work:
/^string\-(\d{1,1})[1-4]$/
Any guidelines? Thanks!
You should just use:
/^string-[1-4]$/
Match the start of the string followed by the word "string-", followed by a single number, 1 to 4 and the end of the string. This will match only this string and nothing else.
If this is part of a larger string and all you want is the one part you can use something like:
/string-[1-4]\b/
which matches pretty much the same as above just as part of a larger string.
You can (in either option) also wrap the character class ([1-4]) in parentheses to get that as a separate part of the matches array (when using preg_match/preg_match_all).
This is not hard:
/^string-([1-4]{1})$/

Regex to count the instances of '?' that are in quotes

I'm trying to make a regex that will count every question mark that is inside of quotes. This regex is being tested in javascript but I intend to use it for PHP if that matters. I have something that kind of works but not well enough.
Here it is.
/(\"|\')(([^\"\'\\]|\\.)*)\?(([^\"\'\\]|\\.)*(\"|\'))/g
As you can probably see I also want to ignore escaped quotes.
Say I have the string "hello? \"world?\"". This will return 1 which is correct.
But as for this "hello? \"world??\"". This will also return 1, but what I want is 2. How can I accomplish this?
Also extra love if I can get a regex that is the exact opposite of this (counting question marks that are NOT in quotes).
Here's the whole function used for this test if it helps.
function countTest(str) {
regx = /(\"|\')(([^\"\'\\]|\\.)*)\?(([^\"\'\\]|\\.)*(\"|\'))/g;
test = str.match(regx);
test = test ? test.length : 0;
console.log(test);
}
EDIT:
Also! I noticed from my own typo in this question the string hello \"world?\'" will also return 1. That seems easy to fix though.
So I just tried it, and apparently the reason the 1 is displayed is, because test is treated not as a String, but as an array. So I would replace
test = test ? test.length : 0;
by
test = test ? new String(test).length - 3 * test.length + 1: 0;
In other words, you are subtracting the 3 characters "," from the String value of the array, but add the 1 because there is no comma character for the first array element.
Edit: For the counting question marks outside quotes, just simply subtract the number given above from the number of total question marks in the string.
Edit: for PHP, you would probably use the array_slice function instead of new String(test), with the multiplication and addition constants adjusted as necessary.

RegEx and MySQL basics - replacing a varying part of a string

I have a field in my table that holds a string denoting some object levels, like so:
"<3<"
"<3<5<"
"<3<5<49<"
etc.
I have a function that is to remove a level from such a string, without knowing the position of the level in the string itself. Concretely, I would like to remove "3". The result should be:
"0"
"<5<"
"<5<49<"
If I would, however, want to remove 5, and not 3, the result should be this:
"<3<"
"<3<"
"<3<49<"
Lastly, if I chose to remove 49 instead of 3 or 5, I would like to get this:
"<3<"
"<3<5<"
"<3<5<"
As you can see, the position of the substring that is to be removed varies - sometimes it's the leftmost one, sometimes in the middle, sometimes the rightmost one. What is important after all this is:
If the number I am removing is the only value, enclosed in "less than" signs (as in "<3<" while removing 3), the new result must be 0.
If the number I am removing is not the only value, the only thing that matters is that the final notation stays the same - as in, the entire string must remain enclosed in "less than" symbols, and substrings of multiple "less than" symbols in a row must not happen (as in, "3<<5<" is not allowed).
Is there an easy regex way to handle this with php and mysql, or should I just make 3 manual checks?
P.S. While I may have posed it as such, this is not homework but an actual work issue.
for each line two replacements: (for example, you want to remove "3")
replace "^<3<$" -> "0";
replace "<3" -> "";
You can do it in 2 steps.
Suppose your input is this
"<3<"
"<3<5<"
"<3<5<49<"
and you want to remove number 3:
Step 1. Since the values always start with "<", you can try to replace "<3" with "". Then the input becomes
"<"
"<5<"
"<5<49<"
Step 2. Replace strings which EQUALS "<" with 0. Then you can get
"0"
"<5<"
"<5<49<"
It's the same if you want to remove 5 or 49.
I think you can easily use regex to do these steps.
In the first step:
replace "<3(?=<)"
I'ts important to use lookaheads, otherwise you could be replacing something like *<3*4 and that's not what you want.
Second step:
replace "^<$" with "0"

Categories