strrev() Function and Integers in PHP - php

I've seen a function that checks if a number is a palindrome.
class Solution {
/**
* #param Integer $x
* #return Boolean
*/
function isPalindrome($x) {
return $x >= 0 && $x === (int)strrev($x);
}
}
My question is: while the strrev function should accept a string as an argument, here it takes an integer and works fine. How is this possible?

PHP follows Perl's convention when dealing with arithmetic operations on character variables and not C's. For example, in PHP and Perl $a = 'Z'; $a++; turns $a into 'AA', while in C a = 'Z'; a++; turns a into '[' (ASCII value of 'Z' is 90, ASCII value of '[' is 91). Note that character variables can be incremented but not decremented and even so only plain ASCII alphabets and digits (a-z, A-Z and 0-9) are supported. Incrementing/decrementing other character variables has no effect, the original string is unchanged.
$s = 'W';
for ($n=0; $n<6; $n++) {
echo ++$s . PHP_EOL;
}
The above example will output:
X
Y
Z
AA
AB
AC

Related

Incrementing chars in for loop works, decrementing does not?

So I was doing some exercises and ran across this code (which produces "1. Item A", "2. Item B", etc ):
echo "\n<ol>";
for ($x='A'; $x<'G'; $x++){
echo "<li>Item $x</li>\n";
}
echo "\n</ol>";
Curious, I attempted to do the reverse (which produces an infinite loop of Zs):
echo "\n<ol>";
for ($x = 'Z'; $x > 'M'; $x--){
echo "<li>Item $x</li>\n";
}
echo "\n</ol>";
What have I missed here?
PHP follows Perl's convention when dealing with arithmetic operations
on character variables and not C's. For example, in PHP and Perl $a =
'Z'; $a++; turns $a into 'AA', while in C a = 'Z'; a++; turns a into
'[' (ASCII value of 'Z' is 90, ASCII value of '[' is 91). Note that
character variables can be incremented but not decremented and even so
only plain ASCII alphabets and digits (a-z, A-Z and 0-9) are
supported. Incrementing/decrementing other character variables has no
effect, the original string is unchanged.
from PHP manual link

Why i am not getting correct output.(php)

<?php
$count='a';
for($i=1;$i<=6;$i++)
{
for($j=1;$j<=(7-$i);$j++)
{
echo $count--;
}
echo "<br/>";
}
?>
count++ is working correctly if i set count='a'. but count-- is not working.
what is the reason for it.
Quoting from the friendly manual
PHP follows Perl's convention when dealing with arithmetic operations on character variables and not C's. For example, in PHP and Perl $a = 'Z'; $a++; turns $a into 'AA', while in C a = 'Z'; a++; turns a into '[' (ASCII value of 'Z' is 90, ASCII value of '[' is 91). Note that character variables can be incremented but not decremented and even so only plain ASCII alphabets and digits (a-z, A-Z and 0-9) are supported. Incrementing/decrementing other character variables has no effect, the original string is unchanged.
(my emphasis)
Try this:
$count='a';
for($i=1;$i<=6;$i++)
{
for($j=1;$j<=(7-$i);$j++)
{
charMinus($count);
echo $count;
}
echo "<br/>";
}
function charMinus(&$char) {
$ascii=ord($char);
$ascii==97 ? $ascii=123;
$char=chr($ascii-1);
}

Why 2a0++ equals 2a1, BUT 2e0++ equals 3?

Code:
$a = "2c0";
for($i = 0; $i < 25; $i++) {
print "$a ";
$a++;
}
Output:
2c0
2c1
2c2
2c3
2c4
2c5
2c6
2c7
2c8
2c9
2d0
2d1
2d2
2d3
2d4
2d5
2d6
2d7
2d8
2d9
2e0
3
4
5
6
Why, php?
2e0 is interpreted as 2 * 10^0 (see PHP exponentiation) which is 2. The next value would therefore be 3.
From the manual:
PHP follows Perl's convention when dealing with arithmetic operations on character variables and not C's. For example, in PHP and Perl $a = 'Z'; $a++; turns $a into 'AA', while in C a = 'Z'; a++; turns a into '[' (ASCII value of 'Z' is 90, ASCII value of '[' is 91). Note that character variables can be incremented but not decremented and even so only plain ASCII alphabets and digits (a-z, A-Z and 0-9) are supported. Incrementing/decrementing other character variables has no effect, the original string is unchanged.
Using the ++ operator on "2c0" causes PHP to increment the string value, thus "2c1". "2e0" is treated as scientific notation, i.e., 2 * 10^0 = 2, so incrementing that gives 3.
See this blog post: http://blog.rstack.cc/post/2a0_misunderstanding - it explains the problem and links the php docs for reference.

Understanding why php increments characters the way it does

PHP Manual states:
PHP follows Perl's convention when dealing with arithmetic operations on character variables and not C's.
For example, in PHP and Perl $a = 'Z'; $a++; turns $a into 'AA',
while in C a = 'Z'; a++; turns a into '['
(ASCII value of 'Z' is 90, ASCII value of '[' is 91).
If PHP converts the characters to ascii values (assuming) when dealing with arithmetic operations on characters, should it not print '[' instead of AA? Why and how does PHP increment characters the way it does?
If PHP converts the characters to ascii values (assuming) when dealing with arithmetic operations on characters ...
Your assumption is false, since it treats "0" and 0 as equal, instead of "0" and 48.
$ php
<?php
echo "0" == 0 ; echo "\n";
echo "0" == 48 ; echo "\n";
1
​

How to increment letters like numbers in PHP?

I would like to write a function that takes in 3 characters and increments it and returns the newly incremented characters as a string.
I know how to increase a single letter to the next one but how would I know when to increase the second letters and then stop and then increase the first letter again to have a sequential increase?
So if AAA is passed, return AAB. If
AAZ is passed return ABA (hard part).
I would appreciate help with the logic and what php functions will be useful to use.
Even better, has some done this already or there is a class available to do this??
Thanks all for any help
Character/string increment works in PHP (though decrement doesn't)
$x = 'AAZ';
$x++;
echo $x; // 'ABA'
You can do it with the ++ operator.
$i = 'aaz';
$i++;
print $i;
aba
However this implementation has some strange things:
for($i = 'a'; $i < 'z'; $i++) print "$i ";
This will print out letters from a to y.
for($i = 'a'; $i <= 'z'; $i++) print "$i ";
This will print out lettes from a to z and it continues with aa and ends with yz.
As proposed in PHP RFC: Strict operators directive
(currently Under Discussion):
Using the increment function on a string will throw a TypeError when strict_operators is enabled.
Whether or not the RFC gets merged, PHP will sooner or later go that direction of adding operator strictness. Therefore, you should not be incrementing strings.
a-z/A-Z ranges
If you know your letters will stay in range a-z/A-Z (not surpass z/Z), you can use the solution that converts letter to ASCII code, increments it, and converts back to letter.
Use ord() a chr():
$letter = 'A';
$letterAscii = ord($letter);
$letterAscii++;
$letter = chr($letterAscii); // 'B'
ord() converts the letter into ASCII num representation
that num representation is incremented
using chr() the number gets converted back to the letter
As discovered in comments, be careful. This iterates ASCII table so from Z (ASCII 90), it does not go to AA, but to [ (ASCII 91).
Going beyond z/Z
If you dare to go further and want z became aa, this is what I came up with:
final class NextLetter
{
private const ASCII_UPPER_CASE_BOUNDARIES = [65, 91];
private const ASCII_LOWER_CASE_BOUNDARIES = [97, 123];
public static function get(string $previous) : string
{
$letters = str_split($previous);
$output = '';
$increase = true;
while (! empty($letters)) {
$letter = array_pop($letters);
if ($increase) {
$letterAscii = ord($letter);
$letterAscii++;
if ($letterAscii === self::ASCII_UPPER_CASE_BOUNDARIES[1]) {
$letterAscii = self::ASCII_UPPER_CASE_BOUNDARIES[0];
$increase = true;
} elseif ($letterAscii === self::ASCII_LOWER_CASE_BOUNDARIES[1]) {
$letterAscii = self::ASCII_LOWER_CASE_BOUNDARIES[0];
$increase = true;
} else {
$increase = false;
}
$letter = chr($letterAscii);
if ($increase && empty($letters)) {
$letter .= $letter;
}
}
$output = $letter . $output;
}
return $output;
}
}
I'm giving you also 100% coverage if you intend to work with it further. It tests against original string incrementation ++:
/**
* #dataProvider letterProvider
*/
public function testIncrementLetter(string $givenLetter) : void
{
$expectedValue = $givenLetter;
self::assertSame(++$expectedValue, NextLetter::get($givenLetter));
}
/**
* #return iterable<array<string>>
*/
public function letterProvider() : iterable
{
yield ['A'];
yield ['a'];
yield ['z'];
yield ['Z'];
yield ['aaz'];
yield ['aaZ'];
yield ['abz'];
yield ['abZ'];
}
To increment or decrement in the 7bits 128 chars ASCII range, the safest:
$CHAR = "l";
echo chr(ord($CHAR)+1)." ".chr(ord($CHAR)-1);
/* m k */
So, it is normal to get a backtick by decrementing a, as the ascii spec list
Print the whole ascii range:
for ($i = 0;$i < 127;$i++){
echo chr($i);
}
/* !"#$%&'()*+,-./0123456789:;<=>?#ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ */
More infos about ANSI 7 bits ASCII: man ascii
To increment or decrement in the 8-bits extended 256 chars UTF-8 range.
This is where it starts to differ regarding the host machine charset. but those charsets are all available on modern machines. From php, the safest is to use the php-mbstring extension: https://www.php.net/manual/en/function.mb-chr.php
Extended ASCII (EASCII or high ASCII) character encodings are
eight-bit or larger encodings that include the standard seven-bit
ASCII characters, plus additional characters. https://en.wikipedia.org/wiki/Extended_ASCII
More info, as example: man iso_8859-9
ISO 8859-1 West European languages (Latin-1)
ISO 8859-2 Central and East European languages (Latin-2)
ISO 8859-3 Southeast European and miscellaneous languages (Latin-3)
ISO 8859-4 Scandinavian/Baltic languages (Latin-4)
ISO 8859-5 Latin/Cyrillic
ISO 8859-6 Latin/Arabic
ISO 8859-7 Latin/Greek
ISO 8859-8 Latin/Hebrew
ISO 8859-9 Latin-1 modification for Turkish (Latin-5)
ISO 8859-10 Lappish/Nordic/Eskimo languages (Latin-6)
ISO 8859-11 Latin/Thai
ISO 8859-13 Baltic Rim languages (Latin-7)
ISO 8859-14 Celtic (Latin-8)
ISO 8859-15 West European languages (Latin-9)
ISO 8859-16 Romanian (Latin-10)
Example, we can find the € symbol in ISO 8859-7:
244 164 A4 € EURO SIGN
To increment or decrement in the 16 bits UTF-16 Unicode range:
Here is a way to generate the whole unicode charset, by generating html entities and converting to utf8. Run it online
for ($x = 0; $x < 262144; $x++){
echo html_entity_decode("&#".$x.";",ENT_NOQUOTES,"UTF-8");
}
Same stuff, but the range goes up to (16^4 * 4)!
echo html_entity_decode('!',ENT_NOQUOTES,'UTF-8');
/* ! */
echo html_entity_decode('"',ENT_NOQUOTES,'UTF-8');
/* " */
To retrieve the unicode € symbol,using the base10 decimal representation of the character.
echo html_entity_decode('€',ENT_NOQUOTES,'UTF-8');
/* € */
The same symbol, using the base16 hexadecimal representation:
echo html_entity_decode('&#'.hexdec("20AC").';',ENT_NOQUOTES,'UTF-8');
/* € */
First 32 bits are reserved for special control characters, output garbage �����, but have a meaning.
You are looking at a number representation problem. This is base24 (or however many numbers your alphabet has). Lets call the base b.
Assign a number to each letter in alphabet (A=1, B=2, C=3).
Next, figure out your input "number": The representation "ABC" means A*b^2 + B*b^1 + C*b^0
Use this formula to find the number (int). Increment it.
Next, convert it back to your number system: Divide by b^2 to get third digit, the remainder (modulo) by b^1 for second digit, the remainder (modulo) by `b^0^ for last digit.
This might help: How to convert from base10 to any other base.
You could use the ASCII codes for alpha numerics. From there you increment and decrement to get the previous/next character.
You could split your string in single characters and then apply the transformations on these characters.
Just some thoughts to get you started.
<?php
$values[] = 'B';
$values[] = 'A';
$values[] = 'Z';
foreach($values as $value ){
if($value == 'Z'){
$value = '-1';
}
$op = ++$value;
echo $op;
}
?>
I have these methods in c# that you could probably convert to php and modify to suit your needs, I'm not sure Hexavigesimal is the exact name for these though...
#region Hexavigesimal (Excel Column Name to Number)
public static int FromHexavigesimal(this string s)
{
int i = 0;
s = s.Reverse();
for (int p = s.Length - 1; p >= 0; p--)
{
char c = s[p];
i += c.toInt() * (int)Math.Pow(26, p);
}
return i;
}
public static string ToHexavigesimal(this int i)
{
StringBuilder s = new StringBuilder();
while (i > 26)
{
int r = i % 26;
if (r == 0)
{
i -= 26;
s.Insert(0, 'Z');
}
else
{
s.Insert(0, r.toChar());
}
i = i / 26;
}
return s.Insert(0, i.toChar()).ToString();
}
public static string Increment(this string s, int offset)
{
return (s.FromHexavigesimal() + offset).ToHexavigesimal();
}
private static char toChar(this int i)
{
return (char)(i + 64);
}
private static int toInt(this char c)
{
return (int)c - 64;
}
#endregion
EDIT
I see by the other answers that in PHP you can use ++ instead, nice!

Categories