Get all text outside parenthesis while capturing word index - php

How can I get all text that's not in parenthesis using preg_match_all? The reason I need to use preg_match_all is because I want to get the index of each word.
Given sentence:
Hello how [t- are] you [t- today], Sir?
I can extract all the words inside the ( ), which works. How can I also get all text outside the ( ) separately?
preg_match_all('/\[t-(.*?)\]/', $this->target, $targetWords, PREG_OFFSET_CAPTURE);
Output:
Array
(
[0] => Array
(
[0] => are
[1] => 47
),
[0] => Array
(
[0] => today
[1] => some number
)
)
Note: I already know about preg_split:
$outsideParenthesis = preg_split('/\[.*?\]/', $this->target);
But this doesn't allow me to maintain the index.
Note 2: It may help to provide my end goal:
I want to take a string of custom markdown. For each word, I want to generate word objects that specify their type and content.
The reason is, I'd like to send an array of word objects in order to the frontend so I can loop through the array and generate HTML elements with classes, so I can apply styling as needed.
And I want to be able to specify any markdown within, e.g.,
Hello how [t- are] you [k- today], Sir?
Where t- is target, k- is key.
So the final array I'd like would look like:
[
[
type => 'normal'
content => 'Hello how '
],
[
type => 'target'
content => 'are'
],
[
type => 'normal'
content => ' you'
]
[
type => 'key'
content => 'today'
]
[
type => 'normal'
content => ', Sir?'
]
]
Here's my wordObjects function as of now:
private function setWordObjects($array, $type)
{
return array_map(function ($n) use ($type) {
return [
'type' => $type,
'content' => $n[0],
'index' => $n[1]
];
}, $array[1]);
}

With preg_match_all
$str = 'Hello how [t- are] you [k- today], Sir?';
$types = ['' => 'normal', 't' => 'target', 'k' => 'key'];
if ( preg_match_all('~ (?| \[ (?<type>[^]-]+) - \h (?<content>[^]]+) ]
| () ([^[]+) ) ~x', $str, $matches, PREG_SET_ORDER) ) {
foreach ($matches as &$m) {
unset($m[0], $m[1], $m[2]);
$m['type'] = $types[$m['type']];
}
print_r($matches);
}
demo

Extended solution:
$s = 'Hello how [t- are] you [k- today], Sir?';
$types = ['t-' => 'target', 'k-' => 'key'];
$splitted = preg_split('/\[([tk]- [^]]+)\]/', $s, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE);
$result = [];
foreach ($splitted as $v) {
[$content, $pos] = $v;
$k = substr($content, 0, 2);
$is_delim = isset($types[$k]);
$result[] = array_combine(['type', 'content', 'index'],
[$is_delim? $types[$k] : 'normal',
$is_delim? substr($content, 3) : $content,
$is_delim? $pos + 3 : $pos]);
}
print_r($result);
The output:
Array
(
[0] => Array
(
[type] => normal
[content] => Hello how
[index] => 0
)
[1] => Array
(
[type] => target
[content] => are
[index] => 14
)
[2] => Array
(
[type] => normal
[content] => you
[index] => 18
)
[3] => Array
(
[type] => key
[content] => today
[index] => 27
)
[4] => Array
(
[type] => normal
[content] => , Sir?
[index] => 33
)
)

Related

Use array_column in combination with preg_match

Lets suppose we have an array of arrays that needs to be converted to rows
From this:
Array
(
[subject] => Array
(
[0] => EDN:LOC:DERR
[1] => EDN:LOC:DOXX
[2] => EDN:LOC:NTTT
[3] => EDN:LOC:NAGA
)
[object] => Array
(
[0] => ABS:D01::ADFPAZ01
[1] => ABS:D01::DOXYWITX
[2] => ABS:D01::NAGBAAD2
[3] => ABS:D01::NAGGAAD2
)
[units] => Array
(
[0] => ABS:D06::UNAA
[1] => ABS:D06::UMMM
[2] => ABS:D06::UPOP
[3] => ABS:D06::UPOP
)
To this:
[0] => "'DERR' , 'ADFPAZ01' , 'UNAA'"
[1] => "'DOXX' , 'DOXYWITX' , 'UMMM'"
[2] => "'NTTT' , 'NAGBAAD2' , 'UPOP'"
[3] => "'NAGA' , 'NAGGAAD2' , 'UPOP'"
So I need the arrays to be cleaned by a pattern and compressed into lines.
I managed the compact view with the following function
$array_res = array();
for ($i=0; $i<=$totalEntries-1; $i++) {
array_push($array_res, implode("', '", array_column($array_of_arrays, $i)));
}
My regex pattern is $pattern = '([^.:]*$)'; And it collects a sequence of letters from the end of the string until it finds a colon. And I used preg_match($pattern, $string, $match) to receive the proper string into the $match variable.
However, I cannot combine the above two procedures either with array_filter or array_map inside the for loop.
EDIT: Note that there can be a subarray that contains values without a colon. In that case we have to get the value as is
[units] => Array
(
[0] => NULL
[1] => VALUE1
[2] => VALUE2
[3] => NULL
)
Rather than using a regex, this just uses array_walk() to process the extracted column and for each item it uses strrchr() with : as the last character to match (although it will include the :, so uses substr() to remove the first char)...
for ($i=0; $i<=$totalEntries-1; $i++) {
$newRow = array_column($array_of_arrays, $i);
array_walk($newRow, function (&$data) {
$data = substr(strrchr(":".$data, ":") , 1);
});
$array_res[] = "'".implode("', '", $newRow)."'";
}
The part ":".$data deals with the time when there is no : in the string, it will always ensure that it does find something to use.
Other way:
$arr = [
'subject' => [ 'EDN:LOC:DERR', 'EDN:LOC:DOXX', 'EDN:LOC:NTTT', 'EDN:LOC:NAGA' ],
'object' => [ 'ABS:D01::ADFPAZ01', 'ABS:D01::DOXYWITX', 'ABS:D01::NAGBAAD2', 'ABS:D01::NAGGAAD2' ],
'units' => [ 'ABS:D06::UNAA', 'ABS:D06::UMMM', 'ABS:D06::UPOP', 'ABS:D06::UPOP' ]
];
$res = [];
$fmt = "'%s', '%s', '%s'";
foreach ($arr['subject'] as $k => $v) {
$res[] = vsprintf($fmt, preg_replace('~^.*:~', '', array_column($arr, $k)));
}
print_r($res);
Notice: If you don't know in advance your array length, nothing forbids to build the format pattern dynamically (using str_repeat or implode).

Show all variables post php if name has exist one word

I want show all post variables if name of variables has start add-
for example: this is a full string with post variables:
Array ( [PartNumber] => sfd [Description] => dsf [Issue] => dfs [Customer] => J.C.B. SERVICE [widget7-table_length] => 5 [add_332/F2684] => [add_333/D1641] => sdf [add_333/D1202] => [add_332/F3144] => sdf [add_332/F3147] => sfd [makeassy] => )
I want to display in array only
[add_332/F2684] => [add_333/D1641] => sdf [add_333/D1202] => [add_332/F3144] => sdf [add_332/F3147] => sfd
I'm trying
print_r($_POST['add_%']);
But, how you see this post, it's not working. Do you have any ideas ?
Use array_filter to extract specific array keys:
$output = array_filter($_POST, function($e) {
return strpos($e, 'add_') === 0;
}, ARRAY_FILTER_USE_KEY);
You coudl try using preg_grep()
$res= preg_grep ('/^add_ (\w+)/i', $_POST);
var_dump($res);
Another Solution with Foreach
<?php
$x = array(
'PartNumber' => 'sfd',
'Description' => 'dsf',
'add_332/F2684' =>'asd',
'add_333/D1641' =>'sdf' ,
'add_333/D1202' => 'asd',
'TESTEST' => 'ASDASD' );
$tmp = array();
foreach($x as $key => $value)
{
if(substr( $key, 0, 3 ) === "add")
{
array_push($tmp,array($key =>$value));
}
}
die(print_r($tmp));
?>
Output:
Array
(
[0] => Array
(
[add_332/F2684] => asd
)
[1] => Array
(
[add_333/D1641] => sdf
)
[2] => Array
(
[add_333/D1202] => asd
)
)
1

Convert string with two delimiters into flat associative array [duplicate]

This question already has answers here:
Explode a string to associative array without using loops? [duplicate]
(10 answers)
Closed 7 months ago.
I'm really have no idea about regex...
So I got stuck... Can anyone give me a solution with explanation of regex itself?
Here is my code:
$str = "id:521082299088|name:JOHNSON GREIG DENOIA|mounth:JAN17|amount:170027|admin:2500|billqty:1|metre:R1/900|usage:00010261-00010550|reffno:0BKP21851AF3EC2E0D4F56997EA19DFA|charge:170377|balace:1935";
$pregsplit = preg_split("/[\s|]+/",$string2);
Output:
Array
(
[0] => id:521082299088
[1] => name:JOHNSON
[2] => GREIG
[3] => DENOIA
[4] => mounth:JAN17
[5] => amount:170027
[6] => admin:2500
[7] => billqty:1
[8] => metre:R1/900
[9] => usage:00010261-00010550
[10] => reffno:0BKP21851AF3EC2E0D4F56997EA19DFA
[11] => charge:170377
[12] => balance:1935
)
I want output like this:
Array
(
"id" => 521082299088
"name" => "JOHNSON GREIG DENOIA"
"mount" => "JAN17"
"amount" => 170027
"admin" => 2500
"billqty" => 1
"metre" => "R1/900"
"usage" => "00010261-00010550"
"reffno" => "0BKP21851AF3EC2E0D4F56997EA19DFA"
"charge" => 170377
"balance" => 1935
)
1) The solution using preg_match_all function with specific regex pattern:
$str = "id:521082299088|name:JOHNSON GREIG DENOIA|mounth:JAN17|amount:170027|admin:2500|billqty:1|metre:R1/900|usage:00010261-00010550|reffno:0BKP21851AF3EC2E0D4F56997EA19DFA|charge:170377|balace:1935";
preg_match_all("/(\w+):([^|]+)/", $str, $matches, PREG_SET_ORDER);
$result = [];
foreach ($matches as $items) {
$result[$items[1]] = $items[2];
}
// $items[1] contains a "parameter" name captured by the first capturing group (\w+)
// $items[2] contains a "parameter" value captured by the second capturing group ([^|]+)
print_r($result);
The output:
Array
(
[id] => 521082299088
[name] => JOHNSON GREIG DENOIA
[mounth] => JAN17
[amount] => 170027
[admin] => 2500
[billqty] => 1
[metre] => R1/900
[usage] => 00010261-00010550
[reffno] => 0BKP21851AF3EC2E0D4F56997EA19DFA
[charge] => 170377
[balace] => 1935
)
(\w+) - matches all alphanumeric characters followed by :
([^|]+) - matches all characters excepting | which is delimiter
http://php.net/manual/en/function.preg-match-all.php
2) In addition to the first approach - using array_combine function(to combine all respective values from two capturing groups):
preg_match_all("/(\w+):([^|]+)/", $str, $matches);
$result = array_combine($matches[1], $matches[2]);
// will give the same result
3) The third alternative approach would be using explode() function:
$result = [];
foreach (explode("|", $str) as $items) {
$pair = explode(":", $items);
$result[$pair[0]] = $pair[1];
}
If you are unable to write regular expression.Here is a simple solution using explode() method.The explode() function breaks a string into an array.
<?php
$str = "id:521082299088|name:JOHNSON GREIG DENOIA|mounth:JAN17|amount:170027|admin:2500|billqty:1|metre:R1/900|usage:00010261-00010550|reffno:0BKP21851AF3EC2E0D4F56997EA19DFA|charge:170377|balace:1935";
$array = explode('|',$str);
foreach($array as $key=>$value){
$data = explode(':',$value);
$final[$data[0]] = $data[1];
}
print_r($final);
?>
Output:
Array
(
[id] => 521082299088
[name] => JOHNSON GREIG DENOIA
[mounth] => JAN17
[amount] => 170027
[admin] => 2500
[billqty] => 1
[metre] => R1/900
[usage] => 00010261-00010550
[reffno] => 0BKP21851AF3EC2E0D4F56997EA19DFA
[charge] => 170377
[balace] => 1935
)
To learn more about explode() read docs http://php.net/manual/en/function.explode.php
A funny way (only if your string doesn't contain = or &): translate pipes to ampersands and colons to equal signs, then parse it as an URL query with parse_str:
$str = "id:521082299088|name:JOHNSON GREIG DENOIA|mounth:JAN17|amount:170027|admin:2500|billqty:1|metre:R1/900|usage:00010261-00010550|reffno:0BKP21851AF3EC2E0D4F56997EA19DFA|charge:170377|balace:1935";
parse_str(strtr($str, ':|', '=&'), $result);
print_r($result);
demo
This approach would be an alternative.
You can separate string and create an array from it using PHP's explode() function. Then you can separate the 'key:value' structure using strpos() and substr() functions.
// input string
$str = "id:521082299088|name:JOHNSON GREIG DENOIA|mounth:JAN17|amount:170027|admin:2500|billqty:1|metre:R1/900|usage:00010261-00010550|reffno:0BKP21851AF3EC2E0D4F56997EA19DFA|charge:170377|balace:1935";
// make an array out of the string, split elements on each pipe character ('|')
$arr = explode('|', $str);
// create an output array to keep the results
$output = [];
// process the array
foreach ($arr as $item) {
// get delimiter
$separatorPos = strpos($item, ':');
// take the key part (The part before the ':')
$key = substr($item, 0, $separatorPos);
// take the value part (The part after the ':')
$value = substr($item, $separatorPos);
// push it into the output array
$output[$key] = $value;
}
// dump the output array
var_export($output);
Dump of the output array would be like follwing;
[
'id' => ':521082299088',
'name' => ':JOHNSON GREIG DENOIA',
'mounth' => ':JAN17',
'amount' => ':170027',
'admin' => ':2500',
'billqty' => ':1',
'metre' => ':R1/900',
'usage' => ':00010261-00010550',
'reffno' => ':0BKP21851AF3EC2E0D4F56997EA19DFA',
'charge' => ':170377',
'balace' => ':1935',
]

Array foreach modification

I have an array $testing like this :
Array (
[CUST_TYPE] =>
Array (
[0] => Family
[1] => Regular
[2] => Corporate
[3] => Premium )
[TOTAL_BALANCE] =>
Array (
[0] => 420946131.01
[1] => 41272033223.93
[2] => 38873647942.4
[3] => 10465337565.61 )
)
I need to convert (print) this array into something like this :
{
cust_type : Family,
balance : 420946131.01
},
{
cust_type : Regular ,
balance : 41272033223.93
},
and so on..
Here is simple foreach that I used, but it can only print cust_type or balance
$cols = array_keys($testing);
foreach ($testing[$cols[1]] as $i => $j) {
echo '{cust_type : ' . $j .
', balance : ' . $<What should I print??> . '},';
}
Kindly please to help.
Thank you.
Consider this snippet,
for($i=0; $i<count($your_array['CUST_TYPE']); $i++)
{
$required[] = [ 'cust_type' => $your_array['CUST_TYPE'][$i],
'balance' => $your_array['TOTAL_BALANCE'][$i] ];
}
$required = json_encode($required);
will output,
[{"cust_type":"Family","balance":420946131.01},{"cust_type":"Regular","balance":41272033223.93},{"cust_type":"Corporate","balance":38873647942.4},{"cust_type":"Premium","balance":10465337565.61}]
For other format, You can use array_combine() creates an array with first argument as keys and second as values,
The format you are specifying is json So, json_encode() will do that for you,
$required = array_combine($your_array['CUST_TYPE'], $your_array['TOTAL_BALANCE']);
$required = json_encode($required);
Now, $required is string with your desired value. Which is,
{"Family":420946131.01,"Regular":41272033223.93,"Corporate":38873647942.4,"Premium":10465337565.61}
Note: Make sure you have same number of members in both $your_array['CUST_TYPE'] and $your_array['TOTAL_BALANCE'] arrays inside your input array. Otherwise you will see a warning.
Using array_map (PHP 4 >= 4.0.6, PHP 5)
$json = json_encode(array_map(function($a,$b){ return array("cust_type"=>$a,"balance"=>$b);},$array["CUST_TYPE"],$array["TOTAL_BALANCE"]));
Test
[akshay#localhost tmp]$ cat test.php
<?php
$array = array(
"CUST_TYPE" => array(
'Family',
'Regular',
'Corporate',
'Premium'
),
"TOTAL_BALANCE" => array(
420946131.01,
41272033223.93,
38873647942.4 ,
10465337565.61
)
);
// PHP 4,5
$json = json_encode(array_map(function($a,$b){ return array("cust_type"=>$a,"balance"=>$b);},$array["CUST_TYPE"],$array["TOTAL_BALANCE"]),JSON_PRETTY_PRINT);
// Input
print_r($array);
// Output
print $json."\n";
?>
Output
[akshay#localhost tmp]$ php test.php
Array
(
[CUST_TYPE] => Array
(
[0] => Family
[1] => Regular
[2] => Corporate
[3] => Premium
)
[TOTAL_BALANCE] => Array
(
[0] => 420946131.01
[1] => 41272033223.93
[2] => 38873647942.4
[3] => 10465337565.61
)
)
[
{
"cust_type": "Family",
"balance": 420946131.01
},
{
"cust_type": "Regular",
"balance": 41272033223.93
},
{
"cust_type": "Corporate",
"balance": 38873647942.4
},
{
"cust_type": "Premium",
"balance": 10465337565.61
}
]

Sorting an array according to some duplicate values in PHP

I have an array containing strings of this format:
[0] => "title|url|score|user|date"
[1] => "title|url|score|user|date"
[2] => "title|url|score|user|date"
[3] => "title|url|score|user|date"
...
The score field is an int that is not always unique (for example, more than one entry can have a score of 0). I'm looking to sort the strings in this array based on their score value. Originally, I tried iterating through the array and making a new one with keys corresponding to the vote score. I soon realized that you can't have duplicate keys in an array.
Is there a good clean way of doing this?
$array = array(
0 => "title|url|12|user|date",
1 => "title|url|0|user|date",
2 => "title|url|13|user|date",
3 => "title|url|0|user|date"
);
function sortOnScore( $a, $b )
{
// discard first two values
list( ,,$scoreA ) = explode( '|', $a );
list( ,,$scoreB ) = explode( '|', $b );
return $scoreA == $scoreB ? 0 : ( $scoreA > $scoreB ? 1 : -1 );
}
usort( $array, 'sortOnScore' );
var_dump( $array );
Look into PHP's usort function
function score_sort($rec1, $rec2)
{
return $rec1['score'] - $rec2['score'];
}
usort($score_array);
Replace ['score'] with however you are extracting the scores from the strings
First you need to turn the strings into arrays with explode so you can do the comparisons:
// If using PHP >= 5.3, this can also be made into an anonymous function
function converter($string) {
$result = array_combine(
array('title', 'url', 'score', 'user', 'date'),
explode('|', $string)
);
// When these are later compared, it should be as numbers
$result['score'] = (int)$result['score'];
return $result;
}
$input = array(
'Foo|http://foo|0|user1|today',
// etc.
);
$converted = array_map('converter', $input);
This will make $converted look like:
array (
0 => array (
'title' => 'Foo',
'url' => 'http://foo',
'score' => '0',
'user' => 'user1',
'date' => 'today',
),
)
Then you can sort the array using the code from my answer here by easily specifying any sort criteria you want:
usort($converted, make_converter('score', 'date', 'title'));
Personally I'd be tempted to iterate through the array, split it by the |'s and put it into a new multi-dimensional array, for example something like this:
[0] => array([title]=>'title',[url]=>'url',[score]=>'score',[user]=>'user',[date]=>'date')
[1] => array([title]=>'title',[url]=>'url',[score]=>'score',[user]=>'user',[date]=>'date')
Then it becomes easy to sort, just use a function like this:
function sortmulti ($array, $index, $order, $natsort=FALSE, $case_sensitive=FALSE) {
if(is_array($array) && count($array)>0) {
foreach(array_keys($array) as $key) {
$temp[$key]=$array[$key][$index];
}
if(!$natsort) {
if ($order=='asc') {
asort($temp);
} else {
arsort($temp);
}
}
else
{
if ($case_sensitive===true) {
natsort($temp);
} else {
natcasesort($temp);
}
if($order!='asc') {
$temp=array_reverse($temp,TRUE);
}
}
foreach(array_keys($temp) as $key) {
if (is_numeric($key)) {
$sorted[]=$array[$key];
} else {
$sorted[$key]=$array[$key];
}
}
return $sorted;
}
return $sorted;
}
i.e. do this:
$sortedarray = sortmulti($array,'score','asc');
It would be very easy using the asort function:
$pattern = '#^([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)$#';
$sorted = array();
foreach($data as $s) $sorted[] = preg_replace($pattern, '$3|$1|$2|$4|$5', $s);
asort($sorted);
these 4 lines of code, when given $data:
Array
(
[0] => title_0|url_0|6|user_0|date_0
[1] => title_1|url_1|6|user_1|date_1
[2] => title_2|url_2|2|user_2|date_2
[3] => title_3|url_3|3|user_3|date_3
[4] => title_4|url_4|2|user_4|date_4
[5] => title_5|url_5|7|user_5|date_5
[6] => title_6|url_6|3|user_6|date_6
[7] => title_7|url_7|8|user_7|date_7
[8] => title_8|url_8|3|user_8|date_8
[9] => title_9|url_9|9|user_9|date_9
)
will generate $sorted:
Array
(
[2] => 2|title_2|url_2|user_2|date_2
[4] => 2|title_4|url_4|user_4|date_4
[3] => 3|title_3|url_3|user_3|date_3
[6] => 3|title_6|url_6|user_6|date_6
[8] => 3|title_8|url_8|user_8|date_8
[0] => 6|title_0|url_0|user_0|date_0
[1] => 6|title_1|url_1|user_1|date_1
[5] => 7|title_5|url_5|user_5|date_5
[7] => 8|title_7|url_7|user_7|date_7
[9] => 9|title_9|url_9|user_9|date_9
)
and with just 2 more lines you can have the items in each element of the array back in the original order/format:
$data = array();
foreach($sorted as $s) $data[] = preg_replace($pattern, '$2|$3|$1|$4|$5', $s);
setting $data to:
Array
(
[0] => title_2|url_2|2|user_2|date_2
[1] => title_4|url_4|2|user_4|date_4
[2] => title_3|url_3|3|user_3|date_3
[3] => title_6|url_6|3|user_6|date_6
[4] => title_8|url_8|3|user_8|date_8
[5] => title_0|url_0|6|user_0|date_0
[6] => title_1|url_1|6|user_1|date_1
[7] => title_5|url_5|7|user_5|date_5
[8] => title_7|url_7|8|user_7|date_7
[9] => title_9|url_9|9|user_9|date_9
)
Create a new array of arrays:
[0] => array("score", old_array[0])
Then sort.

Categories