Something wrong with array - php

I'm using this code to get first number and replace it with 0-9, but I always get 0-0-9 result. Then I deleted in array 9 it started to work correct. why it works that way ?
$direction = strtoupper(substr($query_row["Band"],0,1));
$replace = [
'0' => '0-9','1' => '0-9','2' => '0-9','3' => '0-9','4' => '0-9',
'5' => '0-9','6' => '0-9','7' => '0-9','8' => '0-9', '9' => '0-9' ];
$dir= str_replace(array_keys($replace), $replace, $direction);

try this one
$search = array('0','1','2','3','4','5','6','7','8');
$replace = array('0-9','0-9','0-9','0-9','0-9','0-9','0-9','0-9','0-9');
$dir = str_replace($search, $replace, $direction);
and then work around for 9 which depends on your string
mine was 0123456789 so I tried
$dir = str_replace('99', '9,0-9', $dir);
its working on mine

It's explained in the documentation of str_replace():
Caution
Replacement order gotcha
Because str_replace() replaces left to right, it might replace a previously inserted value when doing multiple replacements.
You pass arrays as first two arguments to str_replace(). This is the same as you would call str_replace() repeatedly for each element in the array.
If $direction is not '9' then it replaces it with '0-9'. Then, on the last cycle it replaces '9' from '0-9' with '0-9' (according to the values you passed it).
I would drop the code after the first line and read the first sentence again: "get first number and replace it with 0-9".
If your goal is to get the first character of $query_row["Band"] and replace it with 0-9 if it is a digit (and make it uppercase otherwise) I would write something more simple:
$direction = substr($query_row["Band"], 0, 1);
if (is_numeric($direction)) {
$dir = '0-9';
} else {
$dir = strtoupper($direction);
}

Related

Get the first letter/number of string that is not a special character

I have:
$string = ')(8234##$ABCFG3478&* hello';
And I want to get the first letter/number in the string that is not a special character. In above string, it should be 8.
Is there a non-regex way to do it, and is that way quicker than below working regex?
if (preg_match('/[a-z0-9]/i', $string, $match)) {
$firstLetter = $match[0];
} else {
// no match
}
echo $firstLetter;
You can use strpbrk to check if any non-special character exists in the string and get the substring out of it and print the first character. I have used range and implode to generate the chars list.
<?php
$string = ')(8234##$ABCFG3478&* hello';
$chars = implode("",range('a','z')) . implode("",range('A','Z')) . implode("",range(0,9));
$str = strpbrk($string, $chars);
if($str !== false){
echo $str[0];
}else{
echo "No non-special character found";
}
Demo: https://3v4l.org/nOQl7
So this is kinda far fetched right now, but you can do it in a reverse style. I do not recommend to check every character in the string, that would take way too long.
PHP is pretty quick by replacing stuff in strings. That's why you define a list via array, with all "special character elements" that can actually occur in the string, and string replace them with... NOTHING:
<?php
$string = ')(8234##$ABCFG3478&* hello';
$special_character_list = ['(', ')', ]; // Extend the list if you like
$sanitized_string = str_replace($special_character_list, '', string);
Edit: Another approach, we create a list of allowed characters, to not define endless lists of not allowed characters.
<?php
$string = ')(8234##$ABCFG3478&* hello';
$allowed_characters = array_merge(range('a', 'z'), range('A', 'Z'), range(0,9));
// We replace the valid characters with nothing - the result is: All bad characters
$bad_characters = str_replace($allowed_characters, '', $string);
// We use the bad_characters to remove them from the original string
$sanitized_string = str_replace(str_split($bad_characters), '', $string);
echo $sanitized_string[0];
$string = ')(8234##$ABCFG3478&* hello';
$length = strlen($string);
$firstLetter = null;
for ($i = 0; $i < $length; ++$i) {
if (ctype_alnum($string[$i])) {
$firstLetter = $string[$i];
break;
}
}
This seems to be a little bit faster: https://3v4l.org/M08qg
(But I would prefer your preg_match approach!)
EDIT: And for strings with much more special chars at the beginning, it is much slower! https://3v4l.org/EFdLW
So the performance depends on the average length of special chars at the beginning of the string.
Unless you are doing hundreds of thousands of iterations of this technique, I don't think "speed" should factor into as a decision making criteria.
For me, I place a high importance on directness then readability. For this reason, I probably wouldn't entertain a technique that generated arrays, incorporated a loop, or frankly, made more than one function call. Regex isn't evil (I, for one, love it), so unless there is another single-function technique, I opt for regex every time.
That said, the only non-regex way (that isn't terribly convoluted) that I found is as #rid commented with strcspn().
preg_match() has the benefit of being more concise, arguably easier to read, and will not cause headaches if your project needs to honor multi-byte characters in the future.
strcspn() does not generate a temporary array/variable from which the correct value must be extracted, and is very likely to outperform any preg_ call but not to a noticeable/valuable degree.
Notice that in my demo, the "character mask" seems to accept not more than one range of characters. It would be handy if I could specify A..Za..z0..9, but I was unable to get that to work.
Code: (Demo)
$strings = [
')(8234##$ABCFG3478&* hello', // mix
'456456', // numeric
'ghijkl', // alphabetic
'!##$%^&*(', // non-alphanumeric
];
foreach ($strings as $string) {
var_export(
[
'string' => $string,
'firstAlphaNumeric1' => preg_match('/[a-z0-9]/i', $string, $match) ? $match[0] : null,
'firstAlphaNumeric2' => $string[strcspn($string, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789')] ?? null,
'firstAlphaNumeric3' => $string[strcspn($string, 'A..Zabcdefghijklmnopqrstuvwxyz0123456789')] ?? null,
]
);
echo "\n";
}
Output:
array (
'string' => ')(8234##$ABCFG3478&* hello',
'firstAlphaNumeric1' => '8',
'firstAlphaNumeric2' => '8',
'firstAlphaNumeric3' => '8',
)
array (
'string' => '456456',
'firstAlphaNumeric1' => '4',
'firstAlphaNumeric2' => '4',
'firstAlphaNumeric3' => '4',
)
array (
'string' => 'ghijkl',
'firstAlphaNumeric1' => 'g',
'firstAlphaNumeric2' => 'g',
'firstAlphaNumeric3' => 'g',
)
array (
'string' => '!##$%^&*(',
'firstAlphaNumeric1' => NULL,
'firstAlphaNumeric2' => NULL,
'firstAlphaNumeric3' => NULL,
)
Ultimately, I'd go for preg_match() because I have used it thousands of times in my career as a php dev. Conversely, I've probably used strcspn() a maximum of 1 time in my career (outside of playing around on Stack Overflow) -- so there is a lack of familiarity / intuitive-ness.

PHP Regex - match attribute and value in string

I have an array of possible attributes:
$attributes = ['color','size'];
Part of my URL looks like this:
color-light-grey-size-xs
I would need to get an array of attributes and their values, ie:
$values = [
'color' => 'light-grey',
'size' => 'xs'
]
Is that doable with regex?
A Regular Expression which you have to feed its cluster of attributes ORed:
(\w++)(?>-(\w+-?(?(?!color|size)(?-1))*))
^^^^^^^^^^
Regex live demo
PHP code:
$str = "color-light-grey-test-size-xs";
$attrs = ['color', 'size'];
$array = [];
preg_replace_callback(
"/(\w++)(?>-(\w+-?(?(?!" . implode("|", $attrs) . ")(?-1))*))/",
function($matches) use (&$array) {
$array[$matches[1]] = rtrim($matches[2], '-');
},
$str
);
print_r($array);
PHP live demo
Note: Order is not important at all.
I will tell you something.
ONLY if you know that first value is color and second value is size you can match between it like:
\bcolor\-([\w\d\-]+)-size-([\w\d\-]+)\b
You will get array of 2 matches for color $1 and for size $2
BUT if you don't know how your URL will look, you are in big problem.
You must know what you expect for all URL's and made matches for every combination.
Here is live example: https://regex101.com/r/3daBXx/1

How to Convert $matches Array Output from preg_match_all in PHP

Using preg_match_all I retrieve (as an example) the follow string:
ABC033-101-143-147-175-142115-
Here is the code for that:
if (preg_match_all('#([A-Z]{2}C)((?:[0-9]{3}-){1,10})([0-9]{6})#', $wwalist, $matches))
I am able to get the output I want (033-101-143-147-175-) by using the following code:
$wwaInfo['locationabbrev'][$wwanum] = $matches[2][$keys[$wwanum]];
echo "locationabbrev";
From here, I need to convert the sets of 3 numbers. Every number has a corresponding abbreviation. For example, 033 = FY, 101 = CY, etc. I need locationabbrev to output a string like: "FY-CY-AY-GG-CA" as opposed to the numbers. Any idea how I would go about this?
Thanks for taking a look!
You can use strtr() with array of replacements. For example:
$locationabbrev = '033-101-143-147-175-'; // example data
// array of replacements
$replacements = [
'033' => 'FY',
'101' => 'CY',
// and so on
];
$translatedabbrev = strtr($locationabbrev, $replacements);
echo $translatedabbrev; // your final string
One method that uses explode and foreach.
Again, Tajgeers answer is very good. So unless you have some specific reason choose that.
This is just one more way to do it.
$repl = [
'033' => 'FY',
'101' => 'CY',
'143' => 'AY',
'147' => 'GG',
'175' => 'CA' ];
$locationabbrev = '033-101-143-147-175';
$arr = explode("-", $locationabbrev);
Foreach($arr as &$val){
$val= $repl[$val];
}
$result = implode("-", $arr);
Echo $result;
https://3v4l.org/iolal
Now that I think of it. If you change the regex slightly, you can get the output of the regex as my $arr. Meaning already exploded.
Still the other answer is better. Just a thought.

Correct regex to detect font family names from google font link src

I've been trying to get array of the fonts that I'm enqeueing on my wordpress theme. This is just for testing.
On input:
http://fonts.googleapis.com/css?family=Arimo:400,700|Quicksand:400,700|Cantarell:400,700,400italic,700italic|Muli:300,400,300italic,400italic|Roboto+Slab:400,700|Share:400,700,400italic,700italic|Inconsolata:400,700|Karla:400,700,400italic,700italic|Maven+Pro:400,500,700,900|Roboto+Slab:400,700|Open+Sans:400italic,600italic,700italic,400,600,700
What I need on output is like this:
array(
[0] => 'Arimo',
[1] => 'Quicksand',
[2] => 'Cantarell',
... so on
)
Till now, I have done almost everything but one little problem.
My code:
$input = 'http://fonts.googleapis.com/css?family=Arimo:400,700|Quicksand:400,700|Cantarell:400,700,400italic,700italic|Muli:300,400,300italic,400italic|Roboto+Slab:400,700|Share:400,700,400italic,700italic|Inconsolata:400,700|Karla:400,700,400italic,700italic|Maven+Pro:400,500,700,900|Roboto+Slab:400,700|Open+Sans:400italic,600italic,700italic,400,600,700';
$against = "/[A-Z][a-z]+[\+][A-Z][a-z]+|[A-Z][a-z]+/";
$matches = array()
preg_match_all( $against, $input, $matches );
print_r($matches);
From this, the output is like this:
array(
0 => Arimo
1 => Quicksand
2 => Cantarell
3 => Muli
4 => Roboto+Slab
5 => Share
6 => Inconsolata
7 => Karla
8 => Maven+Pro
9 => Roboto+Slab
10 => Open+Sans
)
There's the + sign where the font name has spaces. I want to get rid of that.
I'm not a regex expert. So, couldn't manage to do that.
Note: I know I could do it with str_replace() but don't want to go through that long process. I want to know if it's possible to escape the + sign through and leave an empty space there when we are collecting matched expressions.
Spaces encoded as plus (+) signs in url. You should decode your url.
$input = urldecode($input);
Without regex:
$query = strtr(substr(parse_url($url, PHP_URL_QUERY),7), '+', ' ');
$result = array_map(function ($i) { return explode(':', $i)[0]; }, explode('|', $query));
With regex:
if (preg_match_all('~(?:\G(?!\A)|[^?&]+[?&]family=)([^:|&]+):[^:|&]*(?:[|&#]|\z)~', strtr($url, '+', ' '), $m))
$result2 = $m[1];
From your code, output is given me something like this.
array([0] => array([0] => Arimo[1] => Quicksand[2] => Cantarell[3] => Muli[4] => Roboto+Slab[5] => Share[6] => Inconsolata[7] => Karla[8] => Maven+Pro[9] => Roboto+Slab[10] => Open+Sans))
if is correct, then i was solve this issue '+'. here is the solution.
$input = 'http://fonts.googleapis.com/css?family=Arimo:400,700|Quicksand:400,700|Cantarell:400,700,400italic,700italic|Muli:300,400,300italic,400italic|Roboto+Slab:400,700|Share:400,700,400italic,700italic|Inconsolata:400,700|Karla:400,700,400italic,700italic|Maven+Pro:400,500,700,900|Roboto+Slab:400,700|Open+Sans:400italic,600italic,700italic,400,600,700';
$against = "/[A-Z][a-z]+[\+][A-Z][a-z]+|[A-Z][a-z]+/";
$matches = array();
$newArr=array();
preg_match_all( $against, $input, $matches );
for($i=0;$i< count($matches);$i++){
for($j=0;$j< count($matches[$i]);$j++){
$string=preg_replace('/[^A-Za-z0-9\-]/', ' ', $matches[$j]);
if($string!=""){
$newArr[]=$string;
}
}
}
print_r($newArr);
In general, you have more than + characters to worry about.
Special characters, such as the ampersand (&), and non-ASCII characters in URL query parameters have to be escaped using percent-encoding (%xx). In addition, when an HTML form is submitted, spaces are encoded using the + character.
For example:
The font family "Jacques & Gilles" would be escaped as:
Jacques+%26+Gilles
The Unicode character U+1E99 (LATIN SMALL LETTER Y WITH RING ABOVE), serialized into octets as UTF-8 (E1 BA 99), would be escaped as:
%e1%ba%99
To do what you want properly, you have to extract the query string from the URL, and use parse_str() to extract the name=value pairs. The parse_str() function will automatically urldecode() the names and values including the + characters.
First, split the URL on the ? character to extract the query string:
$url = 'http://fonts.googleapis.com/css?family=Arimo:400,700|...|Maven+Pro:400,500,700,900|Roboto+Slab:400,700|...';
$a = explode ('?', $url, 2);
if (isset ($a[1])) {
$query = $a[1];
}
You can also use parse_url ($url, PHP_URL_QUERY), but it doesn't buy you much in this case.
Then extract all the parameters:
if (isset ($query)) {
parse_str ($query, $params);
if (isset ($params['family'])) {
/* OK: Extract family names. */
} else {
/* Error: No family parameter found. */
}
} else {
/* Error: No query string found. */
}
Note: You should always specify the second parameter of parse_str() to avoid clobbering existing variables.

str_replace alternative for PHP

In the str_replace manual for PHP it states the following:
Because str_replace() replaces left to right, it might replace a previously inserted value when doing multiple replacements. See also the examples in this document.
Is there an equivalent function that does not have this gotcha or how can I safely do this?
You're looking for strtr ( string $str , array $replace_pairs ).
If given two arguments, the second should be an array in the form array('from' => 'to', ...). The return value is a string where all the occurrences of the array keys have been replaced by the corresponding values. The longest keys will be tried first. Once a substring has been replaced, its new value will not be searched again.
Example from the manual:
<?php
$trans = array("h" => "-", "hello" => "hi", "hi" => "hello");
echo strtr("hi all, I said hello", $trans);
?>
Will output:
hello all, I said hi
Which should be exactly what you need.
Use preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] ) im pretty sure you could make it replace all the values or one if thats what you're asking.
Or you could do it in pieces if theres an order to replace what you want
$value = preg_replace($pattern1, '..', $value);
$value = preg_replace($pattern2, '..', $value);
$value = preg_replace($pattern3, '..', $value);

Categories