php prevent sscanf() from assuming '-' as string - php

It can distinguishes between decimal and '-'
$str = "1995-25";
$pat = sscanf( $str , "%d-%d);
print_r($pat);
It can also distinguish first '-' and following string
$str = "-of";
$pattern = sscanf ( $str , "-%s" );
print_r ( $pattern );
but when it comes to signify '-' in middle of a string
it assumes '-' as string
and more surprisingly the first %s reads it to the last
even considering 4 as string
$str = '-of-america-4';
$pat = sscanf ($str , "-%s-%s-%d");
print_r($pat);
// outputs [0] => of-america-4

%s is a greedy match, you could use %[^-]
<?php
$str = '-of-america-4';
$pat = sscanf($str , '-%[^-]-%[^-]-%d');
print_r($pat);
Array
(
[0] => of
[1] => america
[2] => 4
)

Related

Search in a string and create an array in PHP

How to convert this string
*|text:student:required|*
( * and | is part of string ) into array like this
['text' ,'student','required']
try the following:
$str = '*|text:student:required|*';
$str = preg_replace("/[|*]/", '', $str);
$arr = explode(':', $str);
this simply removes the | AND * from the string using preg_replace() and the turns the string into an array using explode
Here you go:
$str = "|text:student:required|";
$str = trim($str,"|");
$str = trim($str,"*");
$x = explode(':',$str);
print_r($x);die;
The shortest one with preg_split function:
$s = '*|text:student:required|* ';
$result = preg_split('/[*:| ]+/', $s, -1, PREG_SPLIT_NO_EMPTY);
print_r($result);
The output:
Array
(
[0] => text
[1] => student
[2] => required
)
$string = "*|text:student:required|";
$string = str_replace("*", "", str_replace("|","", $string));
$array = explode(':', $string);

separate special characters from numbers in string in php

I have $value = "10,120,152" in string, now i want to put each number in separate variable like $a = 10; $b = 120; $c = 152;
so basically what i am asking is that how to separate , from the numbers in a string.
If the separator is always a , than using explode makes sense. If the separator varies though you could use a regex.
$value = "10,120,152";
preg_match_all('/(\d+)/', $value, $matches);
print_r($matches[1]);
Output:
Array
(
[0] => 10
[1] => 120
[2] => 152
)
Demo: https://eval.in/483906
That \d+ is all continuos numbers.
Regex101 Demo: https://regex101.com/r/rP2bV1/1
A third approach would be using str_getcsv.
$value = "10,120,152";
$numbers = str_getcsv($value, ',');
print_r($numbers);
Output:
Array
(
[0] => 10
[1] => 120
[2] => 152
)
Demo: https://eval.in/483907
$exploded = explode("," , $values);
var_dump($exploded);
Explode(string $delimiter , string $string [, int $limit ])
You can use explode(), it will return an array with the numbers.
$array = explode(',', $value);
Check this one using list
$value = "10,120,152";
$variables = explode("," , $values);
$variables = array_map('intval', $variables);//If you want integers add this line
list($a, $b, $c) = $variables;

String as 2 D array

I'm using PHP, and I get a string from a db with a struct similar to this:
$string = "a:b;c:d;e:f;g:h;" and so on, where a, b, c.. are variables,
a,c and e couldn't be a continuous number, they can be numbers from 1 to 500.
I need to convert this string into an array with this format:
$array [a] == ("b");
$array [c] == ("d");
$array [e] == ("f");
etc...
But I don't know how to get two substring from string (double dot separated, and dot comma separated) and put it into a 2 D string.
Thanks you in advance
To manipulate the keys and the values of the resulting array without foreach loop, you can use array_reduce:
$string = "a:b;c:d;e:f;g:h;";
$array = array_reduce( array_filter( explode( ';', $string ) ), function( $result, $item ) {
$tmp = explode( ':', $item );
$result[$tmp[0]] = $tmp[1];
return $result;
});
output:
Array (
[a] => b
[c] => d
[e] => f
[g] => h
)
not sure what you are asking,but this may helps you
$re = '/(.?):(.?)/';
$str = 'a:b;c:d;e:f;g:h;';
preg_match_all($re, $str, $matches);
print_r(array_combine($matches[1],$matches[2]));
output:
(
[a] => b
[c] => d
[e] => f
[g] => h
)
use explode() which will split a string into an array based on the specified delimiter.
$string = "a:b;c:d;e:f;g:h;";
$temparray = explode(';', $string);
//$temparray now looks like ['a:b', 'c:d', 'e:f']
//use explode() again in a loop to split up each index
$finalarray = array();
foreach($temparray as $arr){
$splitarr = explode(':', $arr);
//$splitarr will look something like ['a', 'b']
//use those values to set the indexes in your final array
$finalarray[$splitarr[0]] = $splitarr[1];
}
$finalarray=array_filter($finalarray);//to remove null values
//print_r($finalarray);
NOTE: Just FYI, because of the trailing ; in your string, you may end up with an extra empty index at the end of your arrays, hence the array_filter() call, thanks #FerozAkbar

Regular expression and create substring for time

I need a regular for time format HH:MM am/pm. I found something like
$time = "HH:MM am";
preg_match('/[\s0]*(\d|1[0-2]):(\d{2})\s*([AaPp][Mm])/xms', $time, $match);
$h = $match[1];
$m = $match[2];
$a = $match[3];
There are lot of regular expression for time. But what i am looking is if someone write aa:mn jk instead of number then it should give $h=aa $m=mn and $a=jk Or if someone keep them blank or partial filled like abcd then $h=abcd $m=null and $a=null.
I solved it using for loop and some if else but hope some can help me to do it using regular expression or using some PHP function.
You're going to need regexp like this ~^(\d{1,2})((?::)(\d{1,2}))?(\s+(am|pm))?$~i
The whole testing code would be:
<?php
$regexp = '~^(\d{1,2})((?::)(\d{1,2}))?(\s+(am|pm))?$~i';
$tests = array(
'18',
'18:00',
'7:03 pm',
'7 pm'
);
$match = array();
foreach( $tests as $test){
preg_match( $regexp, $test, $match);
print_r( $match);
}
And the results:
Array
(
[0] => 18
[1] => 18
)
Array
(
[0] => 18:00
[1] => 18
[2] => :00
[3] => 00
)
Array
(
[0] => 7:03 pm
[1] => 7
[2] => :03
[3] => 03
[4] => pm
[5] => pm
)
Array
(
[0] => 7 am
[1] => 7
[2] =>
[3] =>
[4] => am
[5] => am
)
So you can prepare you final output like:
$hours = isset( $match[1]) ? $match[1] : '00';
$minutes = isset( $match[3]) ? $match[3] : '00';
$am = isset( $match[5]) ? $match[5] : 'am';
If you need explanation of anything please ask in the comment
Using Regex might be a little overkill. Use the explode() function instead.
<?php
$str = 'aa:bb cc'; // or 'abcd'
$a = explode(':', $str);
$b = isset($a[1]) ? explode(' ', $a[1]) : NULL;
$h = $a[0];
$m = isset($b[0]) ? $b[0] : NULL;
$a = isset($b[1]) ? $b[1] : NULL;
var_dump($h, $m, $a);
You were very vague about your requirements, so I don't really know what you're trying to match, but this will match any number of non-: characters and stick it in $h, followed by an optional : and non-space characters which will be put in $m, followed by an optional 0 or more spaces and the remaining characters will be put in $a:
if (!preg_match('/^([^:]+)(:(\S+))?(\s*(.+))?$/i', $input, $matches)) {
// pattern did not match
}
$h = $matches[1];
$m = $matches[3] ?: NULL;
$a = $matches[5] ?: NULL;

Split string by delimiter, but not if it is escaped

How can I split a string by a delimiter, but not if it is escaped? For example, I have a string:
1|2\|2|3\\|4\\\|4
The delimiter is | and an escaped delimiter is \|. Furthermore I want to ignore escaped backslashes, so in \\| the | would still be a delimiter.
So with the above string the result should be:
[0] => 1
[1] => 2\|2
[2] => 3\\
[3] => 4\\\|4
Use dark magic:
$array = preg_split('~\\\\.(*SKIP)(*FAIL)|\|~s', $string);
\\\\. matches a backslash followed by a character, (*SKIP)(*FAIL) skips it and \| matches your delimiter.
Instead of split(...), it's IMO more intuitive to use some sort of "scan" function that operates like a lexical tokenizer. In PHP that would be the preg_match_all function. You simply say you want to match:
something other than a \ or |
or a \ followed by a \ or |
repeat #1 or #2 at least once
The following demo:
$input = "1|2\\|2|3\\\\|4\\\\\\|4";
echo $input . "\n\n";
preg_match_all('/(?:\\\\.|[^\\\\|])+/', $input, $parts);
print_r($parts[0]);
will print:
1|2\|2|3\\|4\\\|4
Array
(
[0] => 1
[1] => 2\|2
[2] => 3\\
[3] => 4\\\|4
)
Recently I devised a solution:
$array = preg_split('~ ((?<!\\\\)|(?<=[^\\\\](\\\\\\\\)+)) \| ~x', $string);
But the black magic solution is still three times faster.
For future readers, here is a universal solution. It is based on NikiC's idea with (*SKIP)(*FAIL):
function split_escaped($delimiter, $escaper, $text)
{
$d = preg_quote($delimiter, "~");
$e = preg_quote($escaper, "~");
$tokens = preg_split(
'~' . $e . '(' . $e . '|' . $d . ')(*SKIP)(*FAIL)|' . $d . '~',
$text
);
$escaperReplacement = str_replace(['\\', '$'], ['\\\\', '\\$'], $escaper);
$delimiterReplacement = str_replace(['\\', '$'], ['\\\\', '\\$'], $delimiter);
return preg_replace(
['~' . $e . $e . '~', '~' . $e . $d . '~'],
[$escaperReplacement, $delimiterReplacement],
$tokens
);
}
Make a try:
// the base situation:
$text = "asdf\\,fds\\,ddf,\\\\,f\\,,dd";
$delimiter = ",";
$escaper = "\\";
print_r(split_escaped($delimiter, $escaper, $text));
// other signs:
$text = "dk!%fj%slak!%df!!jlskj%%dfl%isr%!%%jlf";
$delimiter = "%";
$escaper = "!";
print_r(split_escaped($delimiter, $escaper, $text));
// delimiter with multiple characters:
$text = "aksd()jflaksd())jflkas(('()j()fkl'()()as()d('')jf";
$delimiter = "()";
$escaper = "'";
print_r(split_escaped($delimiter, $escaper, $text));
// escaper is same as delimiter:
$text = "asfl''asjf'lkas'''jfkl''d'jsl";
$delimiter = "'";
$escaper = "'";
print_r(split_escaped($delimiter, $escaper, $text));
Output:
Array
(
[0] => asdf,fds,ddf
[1] => \
[2] => f,
[3] => dd
)
Array
(
[0] => dk%fj
[1] => slak%df!jlskj
[2] =>
[3] => dfl
[4] => isr
[5] => %
[6] => jlf
)
Array
(
[0] => aksd
[1] => jflaksd
[2] => )jfl'kas((()j
[3] => fkl()
[4] => as
[5] => d(')jf
)
Array
(
[0] => asfl'asjf
[1] => lkas'
[2] => jfkl'd
[3] => jsl
)
Note: There is a theoretical level problem: implode('::', ['a:', ':b']) and implode('::', ['a', '', 'b']) result the same string: 'a::::b'. Imploding can be also an interesting problem.
Regex is painfully slow. A better method is removing escaped characters from the string prior to splitting then putting them back in:
$foo = 'a,b|,c,d||,e';
function splitEscaped($str, $delimiter,$escapeChar = '\\') {
//Just some temporary strings to use as markers that will not appear in the original string
$double = "\0\0\0_doub";
$escaped = "\0\0\0_esc";
$str = str_replace($escapeChar . $escapeChar, $double, $str);
$str = str_replace($escapeChar . $delimiter, $escaped, $str);
$split = explode($delimiter, $str);
foreach ($split as &$val) $val = str_replace([$double, $escaped], [$escapeChar, $delimiter], $val);
return $split;
}
print_r(splitEscaped($foo, ',', '|'));
which splits on ',' but not if escaped with "|". It also supports double escaping so "||" becomes a single "|" after the split happens:
Array ( [0] => a [1] => b,c [2] => d| [3] => e )

Categories