I'm trying to achieve a loop over all possible 2 letter combinations.
Something like
foreach(range(aa,zz) as $i) {...}
My current solution is:
foreach (range(a, z) as $first) {
foreach (range(a, z) as $second) {
//all 2 letter combinations
echo $first.$second;
}
}
This makes me worry that if I needed all possible 10 letter combinations, there would be 10 loops involved.
Is there a better way to achieve this?
You could loop over letters using a simple for loop :
for ($letter = 'aa'; $letter != 'aaa'; ++$letter) {
echo $letter . '<br>';
}
Output :
aa
ab
...
zy
zz
$a = array(1,2,3,4,5,6,7,8,9,0);
$b = array('q','r','s','t','u','v','w','x','y','z');
for($i = 26;$i <= 1000;$i++)
echo str_replace($a,$b,base_convert ( $i, 10 , 26))."<br />";
just put in the right starting and end positions.
Related
I have a number that a user will put into a form - 12 digits. Every second digit needs to be replaced - if the digit is:
1 then make it 5
2 then make it 1
3 then make it 6
4 then make it 2
5 then make it 7
6 then make it 3
7 then make it 8
8 then make it 4
0 and 9 stay the same.
So for example:
343608111218 will end up being 383307121417.
Here is an example of what I'm currently doing, but I think it is long winded. This is just for the first number, so I'm assuming I could do something else?
$_POST['number'] = '343608111218';
preg_match_all('~(\d)~', $_POST['number'], $pregs);
if($pregs[1][1] === "1") {
$one = 5;
}
elseif ($pregs[1][1] === "2"){
$one = 1;
}
elseif ($pregs[1][1] === "3"){
$one = 6;
}
elseif ($pregs[1][1] === "4"){
$one = 2;
}
elseif ($pregs[1][1] === "5"){
$one = 7;
}
elseif ($pregs[1][1] === "6"){
$one = 3;
}
elseif ($pregs[1][1] === "7"){
$one = 8;
}
elseif ($pregs[1][1] === "8"){
$one = 4;
}
$rep1 = (array_replace($pregs[1],array(1=>$one)));
If there is a way that I can reduce the amount of code, I would be very grateful. Thank you.
One way of doing it is with preg_replace_callback, passing the match of 2 digits in a row and using strtr to replace the 2nd digit appropriately:
$_POST['number'] = '343608111218';
echo preg_replace_callback('~(\d)(\d)~', function ($m) {
return $m[1] . strtr($m[2], '12345678', '51627384');
}, $_POST['number']);
Output:
323304151114
This is based on the description you gave on how to do replacements. However if your expected output reflects the correct way to do the replacements, the replacements have to be the other way around, which is just a question of changing the order of parameters to strtr:
echo preg_replace_callback('~(\d)(\d)~', function ($m) {
return $m[1] . strtr($m[2], '51627384', '12345678');
}, $_POST['number']);
Output:
383307121417
Demo on 3v4l.org
As you are replacing each digit with another, create a lookup string and use the number as the index to the array, all the positions 0-9 are set - even if they are the same value. As the value is a string, you can just use the value as the position of the string and replace it directly...
$value = $_POST['number'];
$trans = "0516273849";
for ( $i = 1; $i < strlen($value); $i+=2 ) {
$value[$i] = $trans[$value[$i]];
}
echo $value;
Edit:
To achieve what is the 'desired' output (although only a guess as to what this should be) you can change the line to...
$trans = "0246813579";
$transform = array(
0 => 0,
1 => 5,
2 => 1,
3 => 6,
4 => 8,
5 => 7,
6 => 3,
7 => 8,
8 => 4,
9 => 9
);
$number = '343608111218';
$num = array_map('intval', str_split($number));
$i = 1;
foreach ($num as $key => $value) {
if (0 == ($i % 2)) {
echo $transform[$value];
} else {
echo $value;
}
$i++;
}
To modernize and refine Nick's regex script, use \K to eliminate the use of capture groups. Arrow function syntax helps to make the script more concise. (Demo)
echo preg_replace_callback(
'/.\K\d/',
fn($m) => strtr($m[0], '12345678', '51627384'),
$_POST['number']
);
Nigel's answer is optimized for performance. Despite counting the string length on every iteration and unnecessarily replacing certain numbers with the same number, it will perform very swiftly because it only makes iterated calls of count(). Because all characters in the input string and the translation string are expected to be single-byte characters, the cooresponding number in the translation string can be accessed by its offset. Here's my version of Nigel's script (Demo)
$value = '343608111218';
$trans = '0516273849';
for ($i = 1, $len = strlen($value); $i < $len; $i += 2) {
$value[$i] = $trans[$value[$i]];
}
echo $value;
Mujuonly's answer can be boiled down a little further. $var & 1 is a bitwise odd check which is just as cryptic as !($var % 2), but is slightly faster (not noticeably). Casting each character as an integer is not necessary and using a string-type translation source is a more succinct technique. (Demo)
$number = '343608111218';
$trans = '0516273849';
foreach (str_split($number) as $i => $d) {
if ($i & 1) {
$number[$i] = $trans[$d];
}
}
echo $number;
I have this array which links numbers to letters at the moment like this:
1-26 = A-Z
But there is more, 27=AA and 28=AB etc...
so basically when I do this:
var_dump($array[2]); //shows B
var_dump($array[29]); //shows AC
Now this array I made myself but it's becoming way too long. Is there a way to actually get this going on till lets say 32? I know there is chr but I dont think I can use this.
Is there an easier way to actually get this without using this way too long of an array?
It's slower calculating it this way, but you can take advantage of the fact that PHP lets you increment letters in the same way as numbers, Perl style:
function excelColumnRange($number) {
$character = 'A';
while ($number > 1) {
++$character;
--$number;
}
return $character;
}
var_dump(excelColumnRange(2));
var_dump(excelColumnRange(29));
here is the code which you are looking for :
<?php
$start = "A";
$max = 50;
$result = array();
for($i=1; $i<=$max; $i++) {
$result[$i] = $start++;
}
print_r($result);
?>
Ref: http://www.xpertdeveloper.com/2011/01/php-strings-unusual-behaviour/
This should work for you:
Even without any loops. First I calculate how many times the alphabet (26) goes into the number. With this I define how many times it has to str_repleat() A. Then I simply subtract this number and calculate the number in the alphabet with the number which is left.
<?php
function numberToLetter($number) {
$fullSets = (($num = floor(($number-1) / 26)) < 0 ? 0 : $num);
return str_repeat("A", $fullSets) . (($v = ($number-$fullSets*26)) > 0 ? chr($v+64) : "");
}
echo numberToLetter(53);
?>
output:
AAA
I just gave this answer : https://stackoverflow.com/a/25688064/2627459 in order to loop over letters combination, with the following code :
for ($letter = 'a'; ; ++$letter) {
echo $letter . '<br>';
if ($letter == 'zz') break;
}
Which is just working fine.
I then tried to move the break into the for loop comparison, feeling that it would be better :
for ($letter = 'a'; $letter < 'zz'; ++$letter) {
echo $letter . '<br>';
}
But of course, the last value (zz) wasn't showing, so I tried :
for ($letter = 'a'; $letter < 'aaa'; ++$letter) {
echo $letter . '<br>';
}
And I don't know why, but it's giving me the following output :
a
So I tried several entries, and the (weird) results are :
Entry : $letter < 'yz' -
Output : Up to y only
Entry : $letter < 'zzz' -
Output : Up to zzy
I don't get why it works when the chain starts with z, but it fails in any other case (letter).
Morover, in the case of $letter < 'aaa', it displays a, but not the next one. At worst, I would have expected it to fail with a < 'aaa' and so display nothing. But no.
So, where does this behavior come from, am I missing something on how PHP compare these values ?
(I'm not looking for a workaround, but for an explanation. By the way, if any explanation comes with a working code, it's perfect !)
Comparison is alphabetic:
$letter < 'yz'
When you get to y, you increment again and get z..... alphabetically, z is greater than yz
If you use
$letter != 'yz'
for your comparison instead, it will give you up to yy
So
for ($letter = 'a'; $letter !== 'aaa'; ++$letter) {
echo $letter . '<br>';
}
will give from a, through z, aa, ab.... az, ba.... through to zz.
See also this answer and related comments
EDIT
Personally I like incrementing the endpoint, so
$start = 'A';
$end = 'XFD';
$end++;
for ($char = $start; $char !== $end; ++$char) {
echo $char, PHP_EOL;
}
I have the following test code:
<?php
$letter = 'A';
$letter++;
$letter++;
echo $letter.'<br>'; // C
$letter++;
$letter++;
$letter++;
echo $letter.'<br>'; // F
// how to add plus 3 letters
// so that
// $letter + 3 => I
As shown here by using $letter++ or $letter-- I can go up or down a character. Is there a way I can do something like $letter + 3 so it adds up 3 letters.
I know I can make a function with a loop which will add a char by char and at the end I will get the result. But is there a better way?
There might be better solutions but the fastest way I can think of is:
// get ASCII code of first letter
$ascii = ord('A');
// echo letter for +3
echo chr($ascii + 3);
keep in mind that you will get other symbols after Z
Try this...
$letter = ord('A')+3;
echo chr($letter);
Maybe this'll work:
$x = 'G';
$y = range('A','Z');
echo $y[array_search($x,$y)+3];
Old thread but in case someone searches. Create array of letters, needed letter as in spreadsheet.
$alphabet = array('A','B','C','D','E','F','G','H','I','J','K','L','M',..........'AY','AZ');
//add 36 to the letter A
$val = (array_search('A',$alphabet)) + 36;
echo $alphabet[$val]."<BR>";
I don't really like any of these answers as they don't replicate the function of PHP. Below is probably the easiest way to replicate it.
function addLetters($letter,$lettersToAdd){
for ($i=0;$i<$lettersToAdd;$i++){
$letter++;
}
return $letter;
}
echo addLetters('G',4);
echo "\n";
echo addLetters('Z',4);
Gives
K
AD
I am attempting to show data in rows of three like this (notice the number of items will not always be even):
abcd defg hijk
lmno pqrs tuvw
xyz1 2345 6789
1011 1213
I am struggling to get the logic right to do this (this is in a foreach() loop).
I know I have to have some if($i %3 == 0) logic in there.. But I'm a bit stuck.
Can anyone help me out?
$a = array('abcd','defg','hijk','lmno');
for ($i = 0; $i < count($a); $i++) {
if ($i && $i % 3 == 0)
echo '<br />';
echo $a[$i].' ';
}
It's better to use a for loop as:
// run $i for each index in the array.
for($i=0 ; $i<count($arr) ; $i++) {
// if $i is non-zero and is divisible by 3 print a line break.
if ($i && $i % 3 == 0) {
echo "<br />";
}
// print the element at index $i.
echo $arr[$i].' ';
}
Code in action
Pseudo-code since I don't know PHP (and you asked for the logic which tends to be the same across all procedural languages):
perline = 3
i = 0
foreach item in list:
if i > 0 and (i % perline) == 0:
print newline
if (i % perline) != 0:
print space
print item
i = i + 1
This will both output a line separator before elements 3, 6, 9 and so on (first element being 0) and place whatever desired spacing you want before the second and third elements on each line. You can just use a different value for perline to change the number output on each line.