So i'm creating a simple function to mask phone numbers. My phone numbers have a 9 digits and i want preg_replace them with a given mask like 2-2-2-1-2 or 3-2-2-2 and etc.
I tried this:
$mask = explode('-', '3-2-2-2');
$pattern = '';
$replace = '';
foreach ($mask as $key => $value) {
if ($key == 0) {
$pattern = '/\(?(\d{' . $value . '})\)?[- ]';
$replace = '$' . ++$key . '-';
continue;
}
if ($key == count($mask) - 1) {
$pattern .= '?(\d{' . $value . '})/';
$replace .= '$' . ++$key;
break;
}
$pattern .= '?(\d{' . $value . '})[- ]';
$replace .= '$' . ++$key . '-';
}
return preg_replace($pattern, $replace, '902000810');
and the result is 902-00-08-10. Sometimes getting error preg_replace(): No ending delimiter '/' found. How can i refactor this to not getting errors?
Assuming:
$num = '902000810';
$mask = explode('-', '3-2-2-2');
There're other ways than using regex to format a phone number from the mask.
using formatted strings:
$maskPH = array_map(fn($i) => "%{$i}s", $mask);
$formatI = implode('', $maskPH);
$formatO = implode('-', $maskPH);
$result = vsprintf($formatO, sscanf($num, $formatI));
using unpack:
$format = array_reduce($mask, function ($c, $i) {
static $j = 0;
return "{$c}A{$i}_" . $j++ . "/";
});
$result = implode('-', unpack($format, $num));
preg_replace(): No ending delimiter '/' found
means that your pattern does not terminate with a / as last character.
But all three patterns lack proper formatting:
You should modify them accordingly.
From:
$pattern = '/\(?(\d{' . $value . '})\)?[- ]';
$pattern .= '?(\d{' . $value . '})/';
$pattern .= '?(\d{' . $value . '})[- ]';
To:
$pattern = '/\(?(\d{' . $value . '})\)?[- ]/';
$pattern .= '/?(\d{' . $value . '})/';
$pattern .= '/?(\d{' . $value . '})[- ]/';
I have a variable
<?php
$srch_key = 'asdfggfdsa' ;
?>
Now I want to make a separation with comma after 5 letters. For this I have done this code.
<?php
function ref_format($str, $step, $reverse = false) {
if ($reverse)
return strrev(chunk_split(strrev($str), $step, ','));
return chunk_split($str, $step, ',');
}
$passport = ref_format("$srch_key", 5);
echo $passport_key = substr($passport, 0, -1);
?>
The Output seems like this
asdfg,gfdsa
But I want to make the output like this
'asdfg','gfdsa'
How can I make this.
$srch_key = 'asdfggfdsa' ;
$arr = str_split($srch_key, "5");
$res = "'" . implode ( "', '", $arr ) . "'";
echo $res;
You could do this using implode() and str_split():
function ref_format($str, $step, $reverse = false)
{
if ($reverse)
return strrev("'" . implode("','", str_split($str, $step)) . "'");
return "'" . implode("','", str_split($str, $step)) . "'";
}
I'm using var_export to dump output to logs when errors occur. However since the result is in pure text, I don't get a chance to push it through some sort of library like krumo so I can interactively explores the output.
What methods do people have to deal with making var_export text more readable?
Here is my function, it works well for multidimensional arrays:
function VE($varname, $varval, $short_syntax=true, $tag = ' ', $comma='', $end_line="\r\n") {
$res = '';
if($short_syntax){
$begin_array = '[';
$end_array = ']';
} else {
$begin_array = 'array(';
$end_array = ')';
}
$arr = explode('/',$varname);
$dim =count($arr)-1;
$lastKey = end($arr);
if (! is_array($varval)){
if( is_string($varval)) $varval = "'$varval'";
$res .= str_repeat($tag,$dim) . $lastKey . ' => ' . $varval . $comma . $end_line;
}else{
$res .= str_repeat($tag,$dim) . $lastKey . ' => ' . $begin_array . $end_line;
$count_varval = 0;
$dim_varval = count($varval);
foreach ($varval as $key => $val){
$count_varval++;
if($count_varval<$dim_varval) $commma=','; else $commma='';
if( is_string($key)) $key = "'$key'";
$res .= VE ($varname . "/" . $key , $val, $short_syntax, $tag, $commma);
}
$res .= str_repeat($tag,$dim) . $end_array . $comma . $end_line;
}
return $res;
}
$bigarray = array(); // your array
$bb = VE ('$bigarray', $bigarray);
echo "<pre>$bb</pre>";
I hope it helps ;)
i need to extract and show some words before and after a query word, something like google search results, for example:
$str = "hi user! welcome to new php open source world, we are trying to learn you something!";
$query = "new php";
$result = "... welcome to new php open source ...";
i searched google an SO but didn't find a clear answer or maybe my php knowledge was not enough!
is there a workable and easy-to-use function to do this job?
function yourFuncName($str, $query, $numOfWordToAdd) {
list($before, $after) = explode($query, $str);
$before = rtrim($before);
$after = ltrim($after);
$beforeArray = array_reverse(explode(" ", $before));
$afterArray = explode(" ", $after);
$countBeforeArray = count($beforeArray);
$countAfterArray = count($afterArray);
$beforeString = "";
if($countBeforeArray < $numOfWordToAdd) {
$beforeString = implode(' ', $beforeArray);
}
else {
for($i = 0; $i < $numOfWordToAdd; $i++) {
$beforeString = $beforeArray[$i] . ' ' . $beforeString;
}
}
$afterString = "";
if($countAfterArray < $numOfWordToAdd) {
$afterString = implode(' ', $afterArray);
}
else {
for($i = 0; $i < $numOfWordToAdd; $i++) {
$afterString = $afterString . $afterArray[$i] . ' ';
}
}
$string = $beforeString . $query . ' ' . $afterString;
return $string;
}
Output is: user! welcome to new php open source world, ($numOfWordToAdd = 3)
Here is an working example I thing that it is clear what I did and how:
<?php
$str = "hi user! welcome to new php open source world, we are trying to learn you something!";
$query = "new php";
$expl = explode($query, $str);
// items on the left side of middle string
$expl_left = explode(" ", $expl[0]);
$left_cnt = count($expl_left);
$new_left = $expl_left[$left_cnt-3] . " " . $expl_left[$left_cnt-2];
// items on the right side of middle string
$expl_right = explode(" ", $expl[1]);
$new_right = $expl_right[1] . " " . $expl_right[2];
// new string formated
$new = "... " . $new_left . " " . $query . " " . $new_right . " ...";
print $new;
?>
If you have some questions feel free to ask...
$result = preg_replace('/(.+)?([^\s]+.{10}'.$query.'.{10}[^\s]+)(.+)?/', '... $2 ...', $str);
This will return the same result from the same string and query you gave. If the before or after length starts or ends (respectively) in the middle of a word, it will continue until it completes the word before it stops.
Assuming a "word" is any series of non-whitespace characters, the following will extract 3 words on either side of new php out of the string $subject, but accept less if necessary:
if (preg_match('/(?:\S+\s+){1,3}new php(?:\s+\S+){1,3}/', $subject, $regs)) {
$result = $regs[0];
}
Change the 3s to any number you like.
I used the following function with explode:
public static function returnSearch($query, $str, $wordcount) {
$explode = explode($query, $str);
$result = null;
//if explode count is one the query was not found
if (count($explode) == 1) {
$result = implode(' ', array_slice(str_word_count($explode[0], 2), -$wordcount, $wordcount)) . " ";
}
//if explode count is more than one the query was found at least one time
if (count($explode) > 1) {
//check for if the string begins with the query
if (!empty($explode[0])) {
$result = "..." . implode(' ', array_slice(str_word_count($explode[0], 2), -$wordcount, $wordcount)) . " ";
}
$result = $result . $query;
if (!empty($explode[1])) {
$result = $result . " " . implode(' ', array_slice(str_word_count($explode[1], 2), 0, $wordcount)) . "...";
}
}
//return result
return $result;
}
Corrected function from #Can Vural, it wont mess the phrase of the before match and its case insensitive, very usefull to dispaly in php search results:
function render_search_words($str, $query, $numOfWordToAdd) {
list($before, $after) = preg_split("/$query/i", $str);
$before = rtrim($before);
$after = ltrim($after);
$beforeArray = explode(" ", $before);
$afterArray = explode(" ", $after);
$countBeforeArray = count($beforeArray);
$countAfterArray = count($afterArray);
$beforeString = "";
if($countBeforeArray < $numOfWordToAdd) {
$beforeString = implode(' ', $beforeArray);
}
else {
for($i = 0; $i < $numOfWordToAdd; $i++) {
$beforeString = $beforeArray[$i] . ' ' . $beforeString;
}
}
$afterString = "";
if($countAfterArray < $numOfWordToAdd) {
$afterString = implode(' ', $afterArray);
}
else {
for($i = 0; $i < $numOfWordToAdd; $i++) {
$afterString = $afterString . $afterArray[$i] . ' ';
}
}
$string = '...'.$beforeString . ' <span>' . $query . '</span> ' . $afterString.'...';
return $string;
}
I often need to list items separated by comma, space or punctuation, addresses are a classic example (This is overkill for an address and is for the sake of an example!):
echo "L$level, $unit/$num $street, $suburb, $state $postcode, $country.";
//ouput: L2, 1/123 Cool St, Funky Town, ABC 2000, Australia.
As simple as it sounds, is there an easy way to "conditionally" add the custom separators between variables only if the variable exists? Is it necessary to check if each variable is set? So using the above, another address with less detail may output something like:
//L, / Cool St, , ABC , .
A slightly arduous way of checking would be to see if each variable is set and display the punctuation.
if($level){ echo "L$level, "; }
if($unit){ echo "$unit"; }
if($unit && $street){ echo "/"; }
if($street){ echo "$street, "; }
if($suburb){ echo "$suburb, "; }
//etc...
It would be good to have a function that could automatically do all the stripping/formatting etc:
somefunction("$unit/$num $street, $suburb, $state $postcode, $country.");
Another example is a simple csv list. I want to output x items separated by comma:
for($i=0; $i=<5; $i++;){ echo "$i,"; }
//output: 1,2,3,4,5,
In a loop for example, what's the best way of determining the last item of an array or the loop condition is met to not include a comma at the end of the list? One long way around this I've read of is to put a comma before an item, except the first entry something like:
$firstItem = true; //first item shouldn't have comma
for($i=0; $i=<5; $i++;){
if(!$firstItem){ echo ","; }
echo "$i";
$firstItem = false;
}
For your first example, you can use arrays in conjunction with a few of the array methods to get the desired result. For example:
echo join(', ', array_filter(array("L$level", join(' ', array_filter(array(join('/', array_filter(array($unit, $num))), $street))), $suburb, join(' ', array_filter(array($state, $postcode))), $country))) . '.';
This one-liner is quite complicated to read, so one can always wrap the array, array_filter and join calls into a separate method, and use that:
function merge($delimiter)
{
$args = func_get_args();
array_shift($args);
return join($delimiter, array_filter($args));
}
echo merge(', ', "L$level", merge(' ', merge('/', $unit, $num), $street), $suburb, merge(' ', $state, $postcode), $country) . '.';
You need the array_filter calls to remove the empty entries, otherwise the delimeters would still be printed out.
For your second example, add the items to an array, then use join to insert the delimeter:
$arr = array();
for($i=0; $i=<5; $i++)
{
$arr[] = $i;
}
echo(join(',', $arr));
While Phillip's answer addresses your question, I wanted to supplement it with the following blog post by Eric Lippert. Although his discussion is in c#, it applies to any programming language.
There's a simple solution to your second problem:
for($i=0; $i<=5; $i++)
$o .= "$i,";
echo chop($o, ',');
ok, take that! (but not too serious ^^)
<?php
function bothOrSingle($left, $infix, $right) {
return $left && $right ? $left . $infix . $right : ($left ? $left : ($right ? $right : null));
}
function leftOrNull($left, $postfix) {
return $left ? $left . $postfix : null;
}
function rightOrNull($prefix, $right) {
return $right ? $prefix . $right : null;
}
function joinargs() {
$args = func_get_args();
foreach ($args as $key => $arg)
if (!trim($arg))
unset($args[$key]);
$sep = array_shift($args);
return join($sep, $args);
}
$level = 2;
$unit = 1;
$num = 123;
$street = 'Cool St';
$suburb = 'Funky Town';
$state = 'ABC';
$postcode = 2000;
$country = 'Australia';
echo "\n" . '"' . joinargs(', ', rightOrNull('L', $level), bothOrSingle(bothOrSingle($unit, '/', $num), ' ', $street), bothOrSingle($state, ' ', $postcode), bothOrSingle($country, '', '.')) . '"';
// -> "L2, 1/123 Cool St, ABC 2000, Australia."
$level = '';
$unit = '';
$num = '';
$street = 'Cool St';
$suburb = '';
$state = 'ABC';
$postcode = '';
$country = '';
echo "\n" . '"' . joinargs(
', ',
leftOrNull(
joinargs(', ',
rightOrNull('L', $level),
bothOrSingle(bothOrSingle($unit, '/', $num), ' ', $street),
bothOrSingle($state, ' ', $postcode),
$country
),
'.'
)
) . '"';
// -> "Cool St, ABC."
$level = '';
$unit = '';
$num = '';
$street = '';
$suburb = '';
$state = '';
$postcode = '';
$country = '';
echo "\n" . '"' . joinargs(
', ',
leftOrNull(
joinargs(', ',
rightOrNull('L', $level),
bothOrSingle(bothOrSingle($unit, '/', $num), ' ', $street),
bothOrSingle($state, ' ', $postcode),
$country
),
'.'
)
) . '"';
// -> "" (even without the dot!)
?>
yes, i know - looks a bit like brainfuck.
Philip's solution is probably best when working with arrays (if you don't have to filter out empty values), but if you can't use the array functions--for instance, when dealing with query results returned from mysqli_fetch_object()--then one solution is just a simple if statement:
$list = '';
$row=mysqli_fetch_object($result);
do {
$list .= (empty($list) ? $row->col : ", {$row->col}");
} while ($row=mysqli_fetch_object($result));
Or, alternatively:
do {
if (isset($list)) {
$list .= ", {$row->col}";
} else $list = $row->col;
} while ($row=mysqli_fetch_object($result));
To build a list and filter out empty values, I would write a custom function:
function makeList() {
$args = array_filter(func_get_args()); // as per Jon Benedicto's answer
foreach ($args as $item) {
if (isset($list)) {
$list .= ", $item";
} else {
$list = $item;
}
}
if (isset($list)) {
return $list;
} else return '';
}
Then you can call it like so:
$unitnum = implode('/',array_filter(array($unit,$num)));
if ($unitnum || $street) {
$streetaddress = trim("$unitnum $street");
} else $streetaddress = '';
if ($level) {
$level = "L$level";
}
echo makeList($level, $streetaddress, $suburb, $state $postcode, $country).'.';
I always find that its both faster and easier to use the language's array methods. For instance, in PHP:
<?php
echo join(',', array('L'.$level, $unit.'/'.$num,
$street, $suburb, $state, $postcode, $country));
Just take out the last comma, i.e replace it with nothing.
$string1 = "L$level, $unit/$num $street, $suburb, $state $postcode, $country.";
$string1 = eregi_replace(", \.$", "\.", $string1);
echo $string1;
This will do the work.
<?php
$level = 'foo';
$street = 'bar';
$num = 'num';
$unit = '';
// #1: unreadable and unelegant, with arrays
$values = array();
$values[] = $level ? 'L' . $level : null;
// not very readable ...
$values[] = $unit && $num ? $unit . '/' . $num : ($unit ? $unit : ($num ? $num : null));
$values[] = $street ? $street : null;
echo join(',', $values);
// #2: or, even more unreadable and unelegant, with string concenation
echo trim(
($level ? 'L' . $level . ', ' : '') .
($unit && $num ? $unit . '/' . $num . ', ' : ($unit ? $unit . ', ' : ($num ? $num . ', ': '')) .
($street ? $street . ', ': '')), ' ,');
// #3: hey, i didn't even know that worked (roughly the same as #1):
echo join(', ', array(
$level ? 'L' . $level : null,
$unit && $num ? $unit . '/' . $num : ($unit ? $unit : ($num ? $num : null)),
$street ? $street : null
));
?>