Hopefully, this is an easy one. I have an array with lines that contain output from a CSV file. What I need to do is simply remove any commas that appear between double-quotes.
I'm stumbling through regular expressions and having trouble. Here's my sad-looking code:
<?php
$csv_input = '"herp","derp","hey, get rid of these commas, man",1234';
$pattern = '(?<=\")/\,/(?=\")'; //this doesn't work
$revised_input = preg_replace ( $pattern , '' , $csv_input);
echo $revised_input;
//would like revised input to echo: "herp","derp,"hey get rid of these commas man",1234
?>
Thanks VERY much, everyone.
Original Answer
You can use str_getcsv() for this as it is purposely designed for process CSV strings:
$out = array();
$array = str_getcsv($csv_input);
foreach($array as $item) {
$out[] = str_replace(',', '', $item);
}
$out is now an array of elements without any commas in them, which you can then just implode as the quotes will no longer be required once the commas are removed:
$revised_input = implode(',', $out);
Update for comments
If the quotes are important to you then you can just add them back in like so:
$revised_input = '"' . implode('","', $out) . '"';
Another option is to use one of the str_putcsv() (not a standard PHP function) implementations floating about out there on the web such as this one.
This is a very naive approach that will work only if 'valid' commas are those that are between quotes with nothing else but maybe whitespace between.
<?php
$csv_input = '"herp","derp","hey, get rid of these commas, man",1234';
$pattern = '/([^"])\,([^"])/'; //this doesn't work
$revised_input = preg_replace ( $pattern , "$1$2" , $csv_input);
echo $revised_input;
//ouput for this is: "herp","derp","hey get rid of these commas man",1234
It should def be tested more but it works in this case.
Cases where it might not work is where you don't have quotes in the string.
one,two,three,four -> onetwothreefour
EDIT : Corrected the issues with deleting spaces and neighboring letters.
Well, I haven't been lazy and written a small function to do exactly what you need:
function clean_csv_commas($csv){
$len = strlen($csv);
$inside_block = FALSE;
$out='';
for($i=0;$i<$len;$i++){
if($csv[$i]=='"'){
if($inside_block){
$inside_block=FALSE;
}else{
$inside_block=TRUE;
}
}
if($csv[$i]==',' && $inside_block){
// do nothing
}else{
$out.=$csv[$i];
}
}
return $out;
}
You might be coming at this from the wrong angle.
Instead of removing the commas from the text (presumably so you can then split the string on the commas to get the separate elements), how about writing something that works on the quotes?
Once you've found an opening quote, you can check the rest of the string; anything before the next quote is part of this element. You can add some checking here to look for escaped quotes, too, so things like:
"this is a \"quote\""
will still be read properly.
Not exactly an answer you've been looking for - But I've used it for cleaning commas in numbers in CSV.
$csv = preg_replace('%\"([^\"]*)(,)([^\"]*)\"%i','$1$3',$csv);
"3,120", 123, 345, 567 ==> 3120, 123, 345, 567
Related
Background..
This is user input being collected so I need to expect some strange stuff and try to fix up string before passing these into functions. User input is stored into the database similar to so:
{"value":"O'Neil,'Smith',\"O'Reilly\",100"}
So the script pulls these out of the database, json_decodes them, and then now I'm trying to fix those value strings up. Here's the best example of that I can give.
$json = '{"value":"O\'Neil,\'Smith\',\"O\'Reilly\",100"}';
$array = json_decode($json, true);
The Goal..
How could I go about escaping quotes in strings like so:
O'Neil,Smith,O'Reilly,100
"O'Neil","Smith","O'Reilly",100
'O'Neil','Smith','O'Reilly',100
O'Neil,'Smith',"O'Reilly",100
So that I get the following result out of each:
'O\'Neil','Smith','O\'Reilly',100
Values may or may not contain commas. It could just be a single value like O'Neil or 100.
I'm pretty sure preg_replace could so something like this, or even preg_replace_callback, but I'm just not sure how to go about this.
The below do not work at all but I'm thinking one of these approaches should work.
$value = preg_replace('/(.*?)/', '$1', $array['value']);
$value = preg_replace_callback('/(.*?)/', 'addslashes', $array['value']);
I've also tried exploding the strings using the commas and looping the values but that escapes the quotes I don't want to touch as well.
Thanks all!
I think this function will do what you want. It uses preg_match_all to find either a quoted string (single or double, possibly with escaped quotes inside), or a set of non-comma characters. Each of those values is then trimmed of quotes, and any non-escaped single quotes are replaced with escaped ones. Finally non-numeric values are placed into single quotes:
function quote($value) {
preg_match_all('/"(?:\\\\"|[^"])*"|\'(?:\\\\\'|[^\'])*\'|[^,]+/', $value, $values);
foreach ($values[0] as &$value) {
$value = trim($value, "'\"");
$value = preg_replace("/(?<!\\\\)'/", "\\'", $value);
if (!is_numeric($value)) $value = "'$value'";
}
return implode(',', $values[0]);
}
To use with your sample strings:
echo quote("O'Neil,Smith,O'Reilly,100") . PHP_EOL;
echo quote("\"O'Neil\",\"Smith\",\"O'Reilly\",100") . PHP_EOL;
echo quote("'O\'Neil','Smith','O\'Reilly',100") . PHP_EOL;
echo quote("O'Neil,'Smith',\"O'Reilly\",100") . PHP_EOL;
Output:
'O\'Neil','Smith','O\'Reilly',100
'O\'Neil','Smith','O\'Reilly',100
'O\'Neil','Smith','O\'Reilly',100
'O\'Neil','Smith','O\'Reilly',100
Demo on 3v4l.org
I'm quite new to this, and have borrowed some code from another post I found, I don't know if what I am trying to do is the right or the best way, its just how I am "getting" it to work..
This is the code
<?php
$yn = $_POST['YN'];
echo $yn;
$fl='config.php';
/*read operation ->*/ $tmp = fopen($fl, "r"); $content=fread($tmp,filesize($fl)); fclose($tmp);
// here goes your update
$content = preg_replace('/\$yourname = \"(.*?)\";/', '$yourname = ""$YN"";', $content);
/*write operation ->*/ $tmp =fopen($fl, "w"); fwrite($tmp, $content); fclose($tmp);
?>
I am trying to update a config file entry that matches $yourname with the POST result, I can echo $yn and it contains the correct value, but I can't get the variable to work in the regex replace,
$content = preg_replace('/\$yourname = \"(.*?)\";/', '$yourname = ""$yn"";', $content);
so if $yn = karl then im trying to update $yourname = "" in the file to $yourname = "karl"
but I can't get it to work, the closest I get is it updating the file with the variable as text, ie $yourname = "$yn".
hope someone can help
Using what you posted I managed to get it working, thank you so much :)
$content = preg_replace( '/\$yourname = \"(.*?)\";/', '$yourname = "'.$yn.'";', $content);
I would suggest using a pattern like this
preg_replace( '/'.preg_quote( $yourname ).'\s*=\s*\"[^\"]+\";/', $yourname.'="'.$yn.'";', $content);
..'\s*=\s*\"([^\"]+)\";
preg_quote( $yourname ) - escaped variable input ( literal match )
\s* - one or more spaces
= - literal (=)
\s* - one or more space
\" - literal (")
[^\"]+ - match any character not a (") greedy match as many times as possible.
\" - literal (")
; literal (;)
In this case ( because it uses double quotes ), it's (prudent?) better to use concatenation and save the headache of escaping it. No need to be fancy when simplicity will win the day.
Also be wary of mistakes like this $yn vs $YN in php variable names are case sensitive, without that knowledge it can be a major challenge to find the error, because to us humans it looks the same. Of course it doesn't help that file names, class names, functions and methods are case insensitive ( on Windows ). Really not sure if class and method names are case sensitive on linux, I try to avoid the issue and always use the same casing.
Seeing as it looks like the OP possibly wanted $yourname ( literally ) I updated the regx
preg_replace( '/\$yourname\s*=\s*\"[^\"]+\";/', '$yourname="'.$yn.'";', $content);
https://regex101.com/r/yM9cX9/1
I have following issue:
I import WKT dynamicaly from DB into WKT Wicket Javascript library. I must do some substitutions to fit the WKT correctly. Since mysql fetches WKT AsText(SHAPE) i recive several arrays e.g. POLYGON((xxxx)),POLYGON((yyyy)) and so on.
First, I had to remove all "POLYGON" doing
$str = preg_replace('/^POLYGON/', '', $WKT[1]);
and add MULTIPOLYGON before <?php
tag in the wicket. It works.
Second, I must add comma between polygons, preicisely between "))((" brackets:
$str2 = str_replace(array('((', '))'), array('((', ')),'), $str);
It works but last comma remains what "slightly" deforms my multipolygon:
MULTIPOLYGON((xxx)),((yyy)),((zzz)),
How can I remove last comma?
I would be thankful for every regex or some other solution which can solve my problem.
In any string, you can remove the last X if you are sure that no X follows. So, you can use a negative lookahead: (,)(?!.*,), as seen here and replace it with empty string.
$result = preg_replace('/(,)(?!.*,)/', '', $str)
This doesn't look at the context though, it will just remove the last comma of any string, no matter where it is.
Thank you both - your answers were right and very helpful.
The problem was not string replacement. It was more the data fetching from DB.
Mysqli_fetch_array and mysqli_fetch_assoc return stringstringsring or arrayarrayarray for 3 rows fetched. That is why all commas were replaced.
I changed to mysqli_fetch_all ,then did minor replacements for each row (as array) and implode each one as variable. After i merged them into single variable, then I could apply your solutions. It is not sofisticated solution, but if it is packed into function it'll be fine.
($WKT = mysqli_fetch_all($result)) {
$str = preg_replace('/POLYGON/', '', $WKT[0]);
$str1 = preg_replace('/POLYGON/', '', $WKT[1]);
$str2 = preg_replace('/POLYGON/', '', $WKT[2]);
$str3 = implode($str);
$str4 = implode($str1);
$str5 = implode($str2);
$str6 = $str3 . $str4 . $str5;
$str7 = preg_replace('/\)\)/', ')),', $str6);
$str8 = rtrim($str7, ",");
echo $str8;
}
I am trying to use a License PHP System…
I will like to show the status of their license to the users.
The license Server gives me this:
name=Service_Name;nextduedate=2013-02-25;status=Active
I need to have separated the data like this:
$name = “Service_Name”;
$nextduedate = “2013-02-25”;
$status = “Active”;
I have 2 days tring to resolve this problem with preg_match_all but i cant :(
This is basically a query string if you replace ; with &. You can try parse_str() like this:
$string = 'name=Service_Name;nextduedate=2013-02-25;status=Active';
parse_str(str_replace(';', '&', $string));
echo $name; // Service_Name
echo $nextduedate; // 2013-02-25
echo $status; // Active
This can rather simply be solved without regex. The use of explode() will help you.
$str = "name=Service_Name;nextduedate=2013-02-25;status=Active";
$split = explode(";", $str);
$structure = array();
foreach ($split as $element) {
$element = explode("=", $element);
$$element[0] = $element[1];
}
var_dump($name);
Though I urge you to use an array instead. Far more readable than inventing variables that didn't exist and are not explicitly declared.
It sounds like you just want to break the text down into separate lines along the semicolons, add a dollar sign at the front and then add spaces and quotes. I'm not sure you can do that in one step with a regular expression (or at least I don't want to think about what that regular expression would look like), but you can do it over multiple steps.
Use preg_split() to split the string into an array along the
semicolons.
Loop over the array.
Use str_replace to replace each '=' with ' = "'.
Use string concatenation to add a $ to the front and a "; to the end of each string.
That should work, assuming your data doesn't include quotes, equal signs, semicolons, etc. within the data. If it does, you'll have to figure out the parsing rules for that.
I have very, very odd problem with PHP's implode function. It surprisingly adds some white characters (spaces) to one of array's elements.
Here is my code:
$cities = array(...,5792753,...);
$where .= ' AND gr.geo_city IN(' . implode(',', $cities) . ') ';
//it displays something like: ... AND gr.geo_city IN(...,5 792753,...)
//but it should display: ... AND gr.geo_city IN(...,5792753,...)
//PLEASE NOTE SPACES IN THE EXAMPLE ABOVE!!
echo $where;
I have done some debugging and it seems the original values do not contain any white chars. Here is the code I've used to check it:
foreach($cities as $ct)
{
if(strpos($ct,'792753') !== FALSE)
echo $ct;//it displays 5792753, not 5...792753
}
Why does it add these spaces there? Is it some known bug of the implode function?
Thanks!
You almost certainly have those characters in your original array values. As the commenters have said, implode() does nothing strange... Check your data again for hidden tabs or spaces, or other whitespace characters.
If you want to make sure there are no whitespaces, better strip them with some php functions (str_replace, trim, or reg_exp functions).
Implode does not add anything but the given separator.