preg_replace all characters up to a certain one - php

I have a string
&168491968426|mobile|3|100|1&185601651932|mobile|3|120|1&114192088691|mobile|3|555|5&
and i have to delete, say, this part &185601651932|mobile|3|120|1& (starting with amp and ending with amp) knowing only the first number up to vertical line (185601651932)
so that in result i would have
&168491968426|mobile|3|100|1&114192088691|mobile|3|555|5&
How could i do that with PHP preg_replace function. The number of line (|) separated values would be always the same, but still, id like to have a flexible pattern, not depending on the number of lines in between the & sign.
Thanks.
P.S. Also, I would be greatful for a link to a good simply written resource relating regular expressions in php. There are plenty of them in google :) but maybe you happen to have a really great link

preg_replace("/&185601651932\\|[^&]+&/", ...)
Generalized,
$i = 185601651932;
preg_replace("/&$i\\|[^&]+&/", ...);

if you want real flexibility, use preg_replace_callback. http://php.net/manual/en/function.preg-replace-callback.php

Important: don't forget to escape your number using preg_quote():
$string = '&168491968426|mobile|3|100|1&185601651932|mobile|3|120|1&114192088691|mobile|3|555|5&';
$number = 185601651932;
if (preg_match('/&' . preg_quote($number, '/') . '.*?&/', $string, $matches)) {
// $matches[0] contains the captured string
}

It seems to me you ought to be using another data structure than a string to manipulate this data.
I'd want this data in a structure like
Array(
[id] => Array(
[field_1] => value_1
[field_2] => value_2
)
)
Your massive string can be massaged into such a structure by doing something like this:
$data_str = '168491968426|mobile|3|100|1&185601651932|mobile|3|120|1&114192088691|mobile|3|555|5&';
$remove_num = '185601651932';
/* Enter a descriptive name for each of the numbers here
- these will be field names in the data structure */
$field_names = array(
'number',
'phone_type',
'some_num1',
'some_num2',
'some_num3'
);
/* split the string into its parts, and place them into the $data array */
$data = array();
$tmp = explode('&', trim($data_str, '&'));
foreach($tmp as $record) {
$fields = explode('|', trim($record, '|'));
$data[$fields[0]] = array_combine($field_names, $fields);
}
echo "<h2>Data structure:</h2><pre>"; print_r($data); echo "</pre>\n";
/* Now to remove our number */
unset($data[$remove_num]);
echo "<h2>Data after removal:</h2><pre>"; print_r($data); echo "</pre>\n";

Related

PHP - How to search an associative array by matching the key against a regexp

I am currently working on a small script to convert data coming from an external source. Depending on the content I need to map this data to something that makes sense to my application.
A sample input could be:
$input = 'We need to buy paper towels.'
Currently I have the following approach:
// Setup an assoc_array what regexp match should be mapped to which itemId
private $itemIdMap = [ '/paper\stowels/' => '3746473294' ];
// Match the $input ($key) against the $map and return the first match
private function getValueByRegexp($key, $map) {
$match = preg_grep($key, $map);
if (count($match) > 0) {
return $match[0];
} else {
return '';
}
}
This raises the following error on execution:
Warning: preg_grep(): Delimiter must not be alphanumeric or backslash
What am I doing wrong and how could this be solved?
In preg_grep manual order of arguments is:
string $pattern , array $input
In your code $match = preg_grep($key, $map); - $key is input string, $map is a pattern.
So, your call is
$match = preg_grep(
'We need to buy paper towels.',
[ '/paper\stowels/' => '3746473294' ]
);
So, do you really try to find string We need to buy paper towels in a number 3746473294?
So first fix can be - swap'em and cast second argument to array:
$match = preg_grep($map, array($key));
But here comes second error - $itemIdMap is array. You can't use array as regexp. Only scalar values (more strictly - strings) can be used. This leads you to:
$match = preg_grep($map['/paper\stowels/'], $key);
Which is definitely not what you want, right?
The solution:
$input = 'We need to buy paper towels.';
$itemIdMap = [
'/paper\stowels/' => '3746473294',
'/other\sstuff/' => '234432',
'/to\sbuy/' => '111222',
];
foreach ($itemIdMap as $k => $v) {
if (preg_match($k, $input)) {
echo $v . PHP_EOL;
}
}
Your wrong assumption is that you think you can find any item from array of regexps in a single string with preg_grep, but it's not right. Instead, preg_grep searches elements of array, which fit one single regexp. So, you just used the wrong function.

PHP match and replace whole word

Hi I am replacing certain names with different value . Here is values I am replacing "#size-name" and "#size" .But the problem is my code replacing only size first and note name for example
#size = "replaceword"
#size-name = "replaceword2"
But its replacing
#size ="replaceword"
#size-name = "replaceword2-name"
How can I replace whole word not part of it here is my code
$tempOutQuery = preg_replace("/(\b($key)\b)/i" , $value , $tempOutQuery);
$tempOutQuery= str_replace("#".$key ,$value ,$tempOutQuery);
both codes are not working
My Full Code
$val= "Hi I want #size dress which is #size-name";
$tempOutQuery = preg_replace("/(\b(size)\b)/i" ,"replaceword", $tempOutQuery);
$tempOutQuery = preg_replace("/(\b(size-name)\b)/i" ,"replaceword2", $tempOutQuery);
If you could make replace without using regulat expressions, then I would suggest using standart str_replace() with arrays:
$val= "Hi i want #size dress which is #size-name";
$search = array('size-name', 'size');
$replace = array('replaceword2', 'replaceword');
$result = str_replace($search, $replace, $val);
The order of search and replace Strings is important!
You should take care that you replace long search-strings first, and the short strings later.
Here's another option for you, using preg_replace_callback. It's actually very similar to Gennadiy's method. The only real difference is that it's using the preg aspect of PHP (and it's a lot more work). But it's another way to skin the proverbial cat.
<?php
// SET OUR DEFAULT STRING
$string = 'Hi I want #size suit which is #size-name';
// LOOK FOR EITHER size-name OR size AND IF YOU FIND IT ...
// RUN THE FUNCTION 'replace_sizes'
$string = preg_replace_callback('~#(size-name|size)~', 'replace_sizes', $string);
// PRINT OUT OUR MODIFIED STRING
print $string;
// THIS IS THE FUNCTION THAT WILL BE RUN EVERY TIME A MATCH IS FOUND
// EITHER 'size' OR 'size-name' WILL BE STORED IN $m[1]
function replace_sizes($m) {
// SET UP AN ARRAY THAT HAS OUR POTENTIAL MATCHES AS KEYS
// AND THE TEXT WE WANT TO REPLACE WITH AS THE VALUE
$size_text_array = array('size-name' => 'replaceword2', 'size' => 'replaceword');
// RETURN WHATEVER THE VALUE IS BASED ON THE KEY
return $size_text_array[$m[1]];
}
This will print out:
Hi I want replaceword suit which is replaceword2
Here is a working demo:
http://ideone.com/njNTbB
You can try pre_replace() to replace whole word from an item of an array in PHP a shown below.
<?PHP
function removePrepositions($text){
$propositions=array('/\bfor\b/i','/\band\b/i');
if( count($propositions) > 0 ) {
foreach($propositions as $exceptionPhrase) {
$text = preg_replace($exceptionPhrase, '', trim($text));
}
$retval = trim($text);
}
return $retval;
}
?>
See the entire post here

Error parsing regex pattern in php

I want to split a string such as the following (by a divider like '~##' (and only that)):
to=enquiry#test.com~##subject=test~##text=this is body/text~##date=date
into an array containing e.g.:
to => enquiry#test.com
subject => test
text => this is body/text
date => date
I'm using php5 and I've got the following regex, which almost works, but there are a couple of errors and there must be a way to do it in one go:
//Split the string in the url of $text at every ~##
$regexp = "/(?:|(?<=~##))(.*?=.*?)(?:~##|$|\/(?!.*~##))/";
preg_match_all($regexp, $text, $a);
//$a[1] is an array containing var1=content1 var2=content2 etc;
//Now create an array in the form [var1] = content, [var2] = content2
foreach($a[1] as $key => $value) {
//Get the two groups either side of the equals sign
$regexp = "/([^\/~##,= ]+)=([^~##,= ]+)/";
preg_match_all($regexp, $value, $r);
//Assign to array key = value
$val[$r[1][0]] = $r[2][0]; //e.g. $val['subject'] = 'hi'
}
print_r($val);
My queries are that:
It doesn't seem to capture more than 3 different sets of parameters
It is breaking on the # symbol and so not capturing email addresses e.g. returning:
to => enquiry
subject => test
text => this is body/text
I am doing multiple different regex searches where I suspect I would be able to do one.
Any help would be really appreciated.
Thanks
Why are you using regex when there is much simple method to do this by explode like this
$str = 'to=enquiry#test.com~##subject=test~##text=this is body/text~##date=date';
$array = explode('~##',$str);
$finalArr = array();
foreach($array as $val)
{
$tmp = explode('=',$val);
$finalArr[$tmp['0']] = $tmp['1'];
}
echo '<pre>';
print_r($finalArr);

PHP: uploading a text file and processing on the file content

I have a text file containing data/fields which are separated by exact column no. Each new line represents a new row of data.
Example of file content:
John Chow 26 543 Avenue Street
From the above, first 10 columns are for the name. Next two are for age. And the rest are for the address.
I need to segregate those data from the uploaded file and display it to the user in a formatted table, which will later on be inserted into the database upon confirmation by user.
I am new to PHP. I think substr could work.
Please guide me on how to go about it. I am using codeigniter with PHP, but basic steps in plain PHP will do. Thanks
Read every line of the file, and parse the lines with either substr or regular expression:
$data = array();
$h = fopen($uploadedfile,"r");
while (false !== ($line = fgets($h)))
{
/* substring way: */
$data[] = array(
'name' => trim(substr($line,0,10)),
'age' => intval(sbstr($line,10,2),10),
'address' => trim(substr($line,12))
);
/* regular expression way: */
preg_match("'^(.{10})(.{2})(.*)$'",$line,$n);
$data[] = array(
'name' => trim($n[1]),
'age' => intval($n[2],10),
'address' => trim($n3)
);
}
fclose($h);
Then iterate the $data array to display it in a table form.
Edit: what you ask in the comments can be done also with regular expressions. If $val is the parsed 10 character string, then:
$val = preg_replace("'^0*'","",$val);
would replace all leading 0s.
Yes, you should be using substr. This extracts part of the string. Something like:
$name = trim(substr($line, 0, 10));
$age = trim(substr($line, 10, 2));
$addr = trim(substr($line, 12));
I've added trim to remove any extra whitespace.
Umm I suggest you don't use substr, because peoples names are not always going to be the same length so this will create some problems. I think the explode and implode functions would do the trick better for you, they split a string into an array and back.
http://php.net/manual/en/function.explode.php
http://www.php.net/manual/en/function.implode.php
<?PHP
$str = "John Chow 26 543 Avenue Street";
$data = explode(" ", $str);
$first_name = $data[0];
$last_name = $data[1];
$age = $data[2];
$address = implode(" ", array_slice($data, 3));
?>
You can use a regexp:
if (preg_match('/(.{10})(.{2})(.{12})/', $input, $output)) {
var_dump($output);
}

PHP Tokens From a String

Let's say you have a string that looks like this:
token1 token2 tok3
And you want to get all of the tokens (specifically the strings between the spaces), AND ALSO their position (offset) and length).
So I would want a result that looks something like this:
array(
array(
'value'=>'token1'
'offset'=>0
'length'=>6
),
array(
'value'=>'token2'
'offset'=>7
'length'=>6
),
array(
'value'=>'tok3'
'offset'=>14
'length'=>4
),
)
I know that this can be done by simply looping through the characters of the string and I can simpy write a function to do this.
I am wondering, does PHP have anything built-in that will do this efficiently or at least help with part of this?
I am looking for suggestions and appreciate any help given. Thanks
You can use preg_match_all with the PREG_OFFSET_CAPTURE flag:
$str = 'token1 token2 tok3';
preg_match_all('/\S+/', $str, $matches, PREG_OFFSET_CAPTURE);
var_dump($matches);
Then you just need to replace the items in $matches[0] like this:
function update($match) {
return array( 'value' => $value[0], 'offset' => $value[1], 'length' => strlen($value[0]));
}
array_map('update', $matches[0]);
var_dump($matches[0]);
There's a simpler way, in most respects. You'll have a more basic result, but with much less work put in.
Assuming you have tokena tokenb tokenc stored in $data
$tokens = explode(' ', $data);
Now you have an array of tokens separated by spaces. They will be in order, so $tokens[0] = tokena, $tokens[1] = tokenb, etc. You can very easily get the length of any given item by doing strlen($tokens[$index]); If you need to know how many tokens you were passed, use $token_count = count($tokens);
Not as sophisticated, but next to no work to get it.
You could use explode(), which will give you an array of tokens from the string, and strlen() to count the number of characters in the string. As far as I know, I don't think there is a PHP function to tell you where an element is in an array.
To get around the last problem, you could use a counter variable that loops through the explod()ed array (foreach() for for()) and gives each sub-array in the new data it's position.
Someone please correct my if I'm wrong.
James
I like the first answer the most - to use PREG_OFFSET_CAPTURE. In case anyone else is interested, I ended up writing something that does this as well, although I am going to accept the first answer.
Thank you everybody for helping!
function get_words($string) {
$string_chars = str_split($string);
$words = array();
$curr_offset = 0;
foreach($reduced_string_chars as $offset=>$char) {
if ($char == ' ') {
if ($length) $words[] = array('offset'=>$curr_offset,'length'=>$length,'value'=>implode($value_array));
$curr_offset = $offset;
$length = 0;
$value_array = array();
}
else {
$length++;
$value_array[] = $char;
}
}
return $words;
}

Categories