I have a string like:
'word1 \nword2 "word3 \nword4" word5 \nword6'
and I want to became like
'word1
word2 "word3 \nword4" word5
word6'
I couldn't write any success regexp pattern. Is this possible ?
You can use preg_split for this task:
$result = preg_split('/"[^"]*"(*SKIP)(*FAIL)|\s*\\n\s*/', $txt);
You obtain the parts you want in an array, you can make all what you want after. (write a file line by line, implode with a CRLF...)
More informations about (*SKIP) and (*FAIL): Verbs that act after backtracking and failure
It's possible by regex, my way is kinda complex, maybe someone has better solution
$subject = <<<'SUBJECT'
'word1 \nword2 "special \n \"character" word5 \nword6'
SUBJECT;
$callback = function ($matches1) {
if (preg_match_all(
<<<PATTERN
/"(?:\"|[^"])+?"/
PATTERN
, $matches1[0], $matches2, PREG_OFFSET_CAPTURE)) {
$pointer = 0;
$arr = [];
foreach ($matches2[0] as $match2) {
$arr[] = substr($matches1[0], $pointer, $match2[1]);
$arr[] = $match2[0];
$pointer = $match2[1] + strlen($match2[0]);
}
$arr[] = substr($matches1[0], $pointer, strlen($matches1[0]));
foreach ($arr as $key => &$value) {
if (!($key % 2)) {
$value = preg_replace('/\Q\n\E/', "\n", $value);
}
}
return implode('', $arr);
}
return $matches1[0];
};
$result = preg_replace_callback(
<<<PATTERN
/'(?:\'|[^'])+?'/
PATTERN
, $callback, $subject);
file_put_contents('doc.txt', $result);
Related
transactionid=67002 msisdn=12136018066 destination_msisdn=12136018066 country=Canada countryid=701 operator=1Canada operatorid=2350 reference_operator= originating_currency=CAD destination_currency=CAD product_requested=3 actual_product_sent=3 wholesale_price=3.61 retail_price=3.70 balance=9.96 sms_sent=no sms= cid1= cid2= cid3= pin_based=yes pin_option_1=key in : *105* (top-up code) # (press call button) pin_option_2=Click the WIND icon on your phone pin_option_3=to access the menu, and top up in a few quick steps pin_value=3 pin_code=9973 44700 7583 pin_ivr= pin_serial=5500000008 pin_validity=365 authentication_key=1455826552 error_code=0 error_txt=Transaction Good
When we make this into an array we dont want to lose values like pin_code that has spaces within the data like the delimiter of the string which is also a space. Here is my code so far:
$parsed = preg_split('/\s+/',$string);
$page_is = array_shift($parsed_url);
$getVars = array();
foreach($parsed as $argument) {
list($variable,$value) = explode("=",$argument); $getVars[$variable] = $value;
}
The following approach worked for me:
$str = "transactionid=67002 msisdn=12136018066 destination_msisdn=12136018066 country=Canada countryid=701 operator=1Canada operatorid=2350 reference_operator= originating_currency=CAD destination_currency=CAD product_requested=3 actual_product_sent=3 wholesale_price=3.61 retail_price=3.70 balance=9.96 sms_sent=no sms= cid1= cid2= cid3= pin_based=yes pin_option_1=key in : *105* (top-up code) # (press call button) pin_option_2=Click the WIND icon on your phone pin_option_3=to access the menu, and top up in a few quick steps pin_value=3 pin_code=9973 44700 7583 pin_ivr= pin_serial=5500000008 pin_validity=365 authentication_key=1455826552 error_code=0 error_txt=Transaction Good" ;
$parts = explode('=', $str);
$key = array_shift($parts);
$last_value = array_pop($parts);
foreach($parts as $part) {
preg_match('/[a-zA-Z0-9_]+$/', $part, $match);
$next_key = $match[0];
$value = str_replace($next_key, '', $part);
$array[$key] = $value;
$key = $next_key;
}
$array[$key] = $last_value;
$array = array_map('trim', $array);
var_dump($array);
fun with regular expressions:
$regex = '/(\w+)=((?:.(?!\w+=))+)/';
preg_match_all($regex, $str, $matches, PREG_SET_ORDER);
var_dump($matches);
and if you have php 5.5 or greater you can place this cherry on top (bottom)
$values = array_combine(array_column($matches, 1), array_column($matches, 2));
var_cump($values);
I am storing some data in my database in a comma based string like this:
value1, value2, value3, value4 etc...
This is the variables for the string:
$data["subscribers"];
I have a function which on users request can remove their value from the string or add it.
This is how I remove it:
/* Remove value from comma seperated string */
function removeFromString($str, $item) {
$parts = explode(',', $str);
while(($i = array_search($item, $parts)) !== false) {
unset($parts[$i]);
}
return implode(',', $parts);
}
$newString = removeFromString($existArr, $userdata["id"]);
So in the above example, I am removing the $userdata['id'] from the string (if it exists).
My problem is.. how can I add a value to the comma based string?
Best performance for me
function addItem($str, $item) {
return ($str != '' ? $str.',' : '').$item;
}
You can use $array[] = $var; simply do:
function addtoString($str, $item) {
$parts = explode(',', $str);
$parts[] = $item;
return implode(',', $parts);
}
$newString = addtoString($existArr, $userdata["id"]);
function addToString($str, $item) {
$parts = explode(',', $str);
array_push($parts, $str);
return implode(',', $parts);
}
$newString = addToString($existArr, $userdata["id"]);
I am using regex to match pattern. Then pushing matched result using pushToResultSet. In both way of doing, would $resultSet have similar array content? Similar means not
insense of value, but format. I want to use 2nd way in alternative to 1st code.
UPDATE: Example with sample input http://ideone.com/lIaP49
foreach ($words as $word){
$pattern = '/^(?:\((\+?\d+)?\)|(\+\d{0,3}))? ?\d{2,3}([-\.]?\d{2,3} ?){3,4}/';
preg_match_all($pattern, $text, $matches, PREG_OFFSET_CAPTURE );
$this->pushToResultSet($matches);
}
return $resultSet;
Now I am doing this in another way and pushing array in similar way. As $matches is array and here $b is also array, I guess both code are similar
$b = array();
$pattern = '/^(?:\((\+?\d+)?\)|(\+\d{0,3}))? ?\d{2,3}([-\.]?\d{2,3} ?){3,4}/';
foreach ($test as $value)
{
$value = strtolower($value);
// Capture also the numbers so we just concat later, no more string substitution.
$matches = preg_split('/(\d+)/', $value, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
if ($matches)
{
$newValue = array();
foreach ($matches as $word)
{
// Replace if a valid word number.
$newValue[] = (isset($arrwords[$word]) ? $arrwords[$word] : $word);
}
$newValue = implode($newValue);
if (preg_match($pattern, $newValue))
{
$b[] = $value;
$this->pushToResultSet($b);
}
}
}
//print_r($b);
return $resultSet;
UPDATE
ACtual code which I want to replace out with 2nd code in the question:
<?php
class Phone extends Filter{
function parse($text, $words)
{
$arrwords = array(0=>'zero',1=>'one',2=>'two',3=>'three',4=>'four',5=>'five',6=>'six',7=>'seven',8=>'eight',9=>'nine');
preg_match_all('/[A-za-z]+/', $text, $matches);
$arr=$matches[0];
foreach($arr as $v)
{
$v = strtolower($v);
if(in_array($v,$arrwords))
{
$text= str_replace($v,array_search($v,$arrwords),$text);
}
}
//$resultSet = array();
$l = strlen($text);
foreach ($words as $word){
$pattern = '/^(?:\((\+?\d+)?\)|(\+\d{0,3}))? ?\d{2,3}([-\.]?\d{2,3} ?){3,4}/';
preg_match_all($pattern, $text, $matches, PREG_OFFSET_CAPTURE );
//print_r($matches);
}
//print_r($matches);
$this->pushToResultSet($matches);
return $resultSet;
}
}
After running both codes, run PHP's var_dump function on the output variables.
If the printed output matches for your definition of similar array content, then your answer is yes. Otherwise, your answer is no.
I want to use regular expression to filter substrings from this string
eg: hello world #level:basic #lang:java:php #...
I am trying to produce an array with a structure like this:
Array
(
[0]=> hello world
[1]=> Array
(
[0]=> level
[1]=> basic
)
[2]=> Array
(
[0]=> lang
[1]=> java
[2]=> php
)
)
I have tried preg_match("/(.*)#(.*)[:(.*)]*/", $input_line, $output_array);
and what I have got is:
Array
(
[0] => hello world #level:basic #lang:java:php
[1] => hello world #level:basic
[2] => lang:java:php
)
In this case then I will have to apply this regex few times to the indexes and then apply a regex to filter the colon out. My question is: is it possible to create a better regex to do all in one go? what would the regex be? Thanks
You can use :
$array = explode("#", "hello world #level:basic #lang:java:php");
foreach($array as $k => &$v) {
$v = strpos($v, ":") === false ? $v : explode(":", $v);
}
print_r($array);
do this
$array = array() ;
$text = "hello world #level:basic #lang:java:php";
$array = explode("#", $text);
foreach($array as $i => $value){
$array[$i] = explode(":", trim($value));
}
print_r($array);
Got something for you:
Rules:
a tag begins with #
a tag may not contain whitespace/newline
a tag is preceeded and followed by whitespace or line beginning/ending
a tag can have several parts divided by :
Example:
#this:tag:matches this is some text #a-tag this is no tag: \#escaped
and this one tag#does:not:match
Function:
<?php
function parseTags($string)
{
static $tag_regex = '#(?<=\s|^)#([^\:\s]+)(?:\:([^\s]+))*(?=\s|$)#m';
$results = array();
preg_match_all($tag_regex, $string, $results, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
$tags = array();
foreach($results as $result) {
$tag = array(
'offset' => $result[0][1],
'raw' => $result[0][0],
'length' => strlen($result[0][0]),
0 => $result[1][0]);
if(isset($result[2]))
$tag = array_merge($tag, explode(':', $result[2][0]));
$tag['elements'] = count($tag)-3;
$tags[] = $tag;
}
return $tags;
}
?>
Result:
array(2) {
[0]=>array(7) {
["offset"]=>int(0)
["raw"]=>string(17) "#this:tag:matches"
["length"]=>int(17)
[0]=>string(4) "this"
[1]=>string(3) "tag"
[2]=>string(7) "matches"
["elements"]=>int(3)
}
[1]=>array(5) {
["offset"]=>int(36)
["raw"]=>string(6) "#a-tag"
["length"]=>int(6)
[0]=>string(5) "a-tag"
["elements"]=>int(1)
}
}
Each matched tag contains
the raw tag text
the tag offset and original length (e.g. to replace it in the string later with str... functions)
the number of elements (to safely iterate for($i = 0; $i < $tag['elements']; $i++))
This might work for you:
$results = array() ;
$text = "hello world #level:basic #lang:java:php" ;
$parts = explode("#", $text);
foreach($parts as $part){
$results[] = explode(":", $part);
}
var_dump($results);
Two ways using regex, note that you somehow need explode() since PCRE for PHP doesn't support capturing a subgroup:
$string = 'hello world #level:basic #lang:java:php';
preg_match_all('/(?<=#)[\w:]+/', $string, $m);
foreach($m[0] as $v){
$example1[] = explode(':', $v);
}
print_r($example1);
// This one needs PHP 5.3+
$example2 = array();
preg_replace_callback('/(?<=#)[\w:]+/', function($m)use(&$example2){
$example2[] = explode(':', $m[0]);
}, $string);
print_r($example2);
This give you the array structure you are looking for:
<pre><?php
$subject = 'hello world #level:basic #lang:java:php';
$array = explode('#', $subject);
foreach($array as &$value) {
$items = explode(':', trim($value));
if (sizeof($items)>1) $value = $items;
}
print_r($array);
But if you prefer you can use this abomination:
$subject = 'hello world #level:basic #lang:java:php';
$pattern = '~(?:^| ?+#)|(?:\G([^#:]+?)(?=:| #|$)|:)+~';
preg_match_all($pattern, $subject, $matches);
array_shift($matches[1]);
$lastKey = sizeof($matches[1])-1;
foreach ($matches[1] as $key=>$match) {
if (!empty($match)) $temp[]=$match;
if (empty($match) || $key==$lastKey) {
$result[] = (sizeof($temp)>1) ? $temp : $temp[0];
unset($temp);
}
}
print_r($result);
I have a string that looks like this "thing aaaa" and I'm using explode() to split the string into an array containing all the words that are separated by space. I execute something like this explode (" ", $string) .
I'm not sure why but the result is : ["thing","","","","aaaa"]; Does anyone have an idea why I get the three empty arrays in there ?
EDIT : This is the function that I'm using that in :
public function query_databases() {
$arguments_count = func_num_args();
$status = [];
$results = [];
$split =[];
if ($arguments_count > 0) {
$arguments = func_get_args();
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($arguments));
foreach ($iterator as $key => $value) {
array_push($results, trim($value));
}
unset($value);
$filtered = $this->array_unique_values($results, "String");
foreach ($filtered as $key => $string) {
if (preg_match('/\s/',$string)) {
array_push($split, preg_split("/\s/", $string));
} else {
array_push($split, $string);
}
}
unset($string);
echo "Terms : ".json_encode($split)."<br>";
foreach ($filtered as $database) {
echo "Terms : ".json_encode()."<br>";
$_action = $this->get_database($database);
echo "Action : ".json_encode($_action)."<br>";
}
unset($database);
} else {
return "[ Databases | Query Databases [ Missing Arguments ] ]";
}
}
It might be something else that messes up the result ?!
If you are looking to create an array by spaces, you might want to consider preg_split:
preg_split("/\s+/","thing aaaa");
which gives you array ("thing","aaaa");
Taken from here.
try this:
$str = str_replace(" ", ",", $string);
explode(",",$str);
This way you can see if it is just the whitespace giving you the problem if you output 4 commas, it's because you have 4 whitespaces.
As #Barmar said, my trim() just removes all the space before and after the words, so that is why I had more values in the array than I should have had.
I found that this little snippet : preg_replace( '/\s+/', ' ', $value ) ; replacing my trim() would fix it :)