Is it possible to data normalization directly on csv importer array?
I have the following:
foreach($importData_arr as $importData){
// var_dump($importData);
$insertData = array(
"EAN"=>$importData[0], preg_replace('\'', '', "EAN"),
"Brand"=>$importData[1],
"Name"=>$importData[2],
"Size"=>$importData[3],
"PCD"=>$importData[4],
"Offset"=>$importData[5],
"Bore"=>$importData[6],
"Color"=>$importData[7],
"Price"=>$importData[8],
"Stock"=>$importData[9],
"ImageURL"=>$importData[10]);
RimsUpload::insertData($insertData);
But i recerive the error :
preg_replace(): No ending delimiter ''' found
This \' should allow for searching for ' and replacing with 'nothing' in my EAN column, as far as i know. But i am not sure that its possible directly on the array like this?
There's no need for regular expressions when you want to replace one symbol, str_replace will do th job.
Also, preg_replace('\'', '', "EAN"), even with correct delimiters, (e.g. #):
preg_replace('#\'#', '', "EAN")
will return string EAN.
Obviously, you want to replace ' in $importData[0] value.
So your code should be:
$insertData = array(
"EAN" => str_replace('\'', '', $importData[0]),
"Brand"=>$importData[1],
"Name"=>$importData[2],
"Size"=>$importData[3],
"PCD"=>$importData[4],
// ...
And if you still want to use regular expressions (which is redundant here), then provide correct delimiters, e.g.:
$insertData = array(
"EAN" => preg_replace('#\'#', '', $importData[0]),
"Brand"=>$importData[1],
"Name"=>$importData[2],
"Size"=>$importData[3],
"PCD"=>$importData[4],
// ...
Related
I've started with preg_replace in PHP and I wonder how I can replace only first matching array key with a specified array value cause I set preg_replace number of changes parameter to '1' and it's changing more than one time anyways. I also splitted my string to single words and I'm examining them one by one:
<?php
$internal_message = 'Hey, this is awesome!';
$words = array(
'/wesome(\W|$)/' => 'wful',
'/wful(\W|$)/' => 'wesome',
'/^this(\W|$)/' => 'that',
'/^that(\W|$)/' => 'this'
);
$splitted_message = preg_split("/[\s]+/", $internal_message);
$words_num = count($splitted_message);
for($i=0; $i<$words_num; $i++) {
$splitted_message[$i] = preg_replace(array_keys($words), array_values($words), $splitted_message[$i], 1);
}
$message = implode(" ", $splitted_message);
echo $message;
?>
I want this to be on output:
Hey, that is awful
(one suffix change, one word change and stops)
Not this:
Hey, this is awesome
(two suffix changes, two word changes and back to original word & suffix...)
Maybe I can simplify this code? I also can't change order of the array keys and values cause there will be more suffixes and single words to change soon. I'm kinda newbie in php coding and I'll be thankful for any help ;>
You may use plain text in the associative array keys that you will use to create dynamic regex patterns from, and use preg_replace_callback to replace the found values with the replacements in one go.
$internal_message = 'Hey, this is awesome!';
$words = array(
'wesome' => 'wful',
'wful' => 'wesome',
'this' => 'that',
'that' => 'this'
);
$rx = '~(?:' . implode("|", array_keys($words)) . ')\b~';
echo "$rx\n";
$message = preg_replace_callback($rx, function($m) use ($words) {
return isset($words[$m[0]]) ? $words[$m[0]] : $m[0];
}, $internal_message);
echo $message;
// => Hey, that is awful!
See the PHP demo.
The regex is
~(?:wesome|wful|this|that)\b~
The (?:wesome|wful|this|that) is a non-capturing group that matches any of the values inside, and \b is a word boundary, a non-consuming pattern that ensures there is no letter, digit or _ after the suffix.
The preg_replace_callback parses the string once, and when a match occurs, it is passed to the anonymous function (function($m)) together with the $words array (use ($words)) and if the $words array contains the found key (isset($words[$m[0]])) the corresponding value is returned ($words[$m[0]]) or the found match is returned otherwise ($m[0]).
I have this problem:
One string like:
$stringa = "array('name' => 'John')"
I want obtain : array('name' => 'John') for use in my code like array
Any helps? Thanks
Caution using eval...
Caution The eval() language construct is very dangerous because it
allows execution of arbitrary PHP code. Its use thus is discouraged.
If you have carefully verified that there is no other option than to
use this construct, pay special attention not to pass any user
provided data into it without properly validating it beforehand.
<?php
$stringa = "array('name' => 'John')";
$code = "\$a = " . $stringa . ";";
eval($code);
print_r($a);
Gouda Elalfy was on the right idea, but his solution simply made the whole string a single array value.
First, we need to remove the excess datatype information:
$slimString = substr($stringa,6);
$slimString = rtrim($slimString,")");
This now gives us a string of:
'name' => 'John'
So then the Keys and the values in the string need to be split up,
so break at => as so:
For multiple values in the string:
This method also includes the single quotes to limit catching punctuation commas (please note this method was screwed up by trim not being as effective as I'd have liked and requiring str_replace quotes instead).
$slimString = str_replace("', '","=>", $slimString);
Then
$slimStringParts = explode("=>", $slimString);
This will split on => (or ,) so that multiple values of array contents can be generated.
Then cycle through each of the array pieces, on the basis that the EVEN numbers (and zero) are the Keys and the ODD numbers are the values, also removing the quotes as well for each one,
I was originally using trim but for some reason trim was not working as fully as I expected. so instead reverted to st_replace
foreach($slimStringParts as $key => $part){
if(($key%2) == 0){
$part = str_replace("'","",$part);
$arrayOutput[$part] = str_replace("'","",$slimStringParts[$key+1]);
}
}
unset($key, $part);
The foreach only acts upon the even and zero values as referenced above, and they take the original key value + 1 as their contents.
The trim/str_replace removes the single quotes and looks untidy but this works for a string of one or more array values
And finally the Output:
print_r($arrayOutput);
Test with the original:
input : "array('name' => 'John')"
Output : Array ( [name ] => John )
Tested with a multivalue array string:
input : "array('name' => 'John', 'surname' => 'James', 'Ride' => 'horse')"
Output : Array ( [name ] => John [surname ] => James [Ride ] => horse )
Full code:
$stringa = "array('name' => 'John')";
$stringb = "array('name' => 'John', 'surname' => 'James', 'Ride' => 'horse')";
$slimString = substr($stringb,6);
$slimString = rtrim($slimString,")");
$slimString = str_replace("', '","=>", $slimString);
$slimStringParts = explode("=>", $slimString);
foreach($slimStringParts as $key => $part){
if(($key%2) == 0){
$part = str_replace("'","",$part);
$arrayOutput[$part] = str_replace("'","",$slimStringParts[$key+1]);
}
}
unset($key,$part);
print_r($arrayOutput);
exit;
Please note my trim() idea was what I wanted but that seems to be influenced by my page character encoding :-(
You can use eval() function.
But it's not recommanded.
http://php.net/manual/en/function.eval.php
Eval is unsafe, try to use it as temporary method and find a better solution.
Example :
$stringa="array('name' => 'John');";
$array = eval($stringa);
I have many calls like this throughout the code, escaping any backticks on the columns of a row.
htmlentities(str_replace("`", "``", $row['column']), ENT_QUOTES);
I made an addition, requiring the column to replace a #width ##. Since most of these calls happen inline an output, I would like to have a solution in a single line.
I was thinking conditional regex (preg_replace_callback), but is this the best way to achieve that? So what I need is:
replace backticks with 2 backticks, and replace hashes with 2 hashes. (This is for escaping purposes).
str_replace() supports array parameters:
// translation map:
$map = [
'`' => '``',
'#' => '##'
];
// what to replace:
$from = array_keys($map);
// replace by what:
$to = array_values($map);
echo htmlentities(str_replace($from, $to, $row['column']), ENT_QUOTES);
In rare cases, that requires you to minify your code, you may try to use that:
echo htmlentities(str_replace([ '`', '#' ], [ '``', '##' ], $row['column']), ENT_QUOTES));
// ^ ^
// from what by what
As stated in documentation of str_replace, you can use can use arrays:
str_replace(["`", "#"], ["``", "##"], $row['column']);
if someone would prefer to use a regular expression:
preg_replace("/`|#/", "$0$0")
It's easy, just use arrays as params for str_replace
htmlentities(str_replace(array("`","#"), array("``","##"), $row['column']), ENT_QUOTES);
This is primarily a regex question, but it is being used in Codeigniter's routing file. The routing file is a list of regex rules that it tries the match. Thus the need for a 1 liner.
Take the following 4 strings:
techniques/foo3
news/bar-4-22
reviews/non23-a
features/wins
I'm looking for a 1 line, regex rule that will find techniques,news,reviews or features and replace with a particular int value of 5,1,7 or 3. The number corresponds to the name, so techniques=5, news=1, reviews=7 and features=3. The last value after the slash can be any URL friendly text string. I'll be selecting this as well strait as is. I essentially want to convert them to the following:
categorysearch/5/foo3
categorysearch/1/bar-4-22
categorysearch/7/non23-a
categorysearch/3/wins
Can this be done with 1 regex line?
Use preg_replace_callback() like so:
$tokens = [
'techniques' => 5,
'news' => 1,
'reviews' => 7,
'features' => 3
];
echo preg_replace_callback('#^([^/]+)/(.*)$#', function ($m) use ($tokens) {
if (array_key_exists($m[1], $tokens)) {
return sprintf('%s/%d/%s', $m[1], $tokens[$m[1]], $m[2]);
}
return sprintf('%s/%s', $m[1], $m[2]);
}, $string);
If the replacement is simple as this, a regex is not even required. A simple sscanf() or explode() (with the list construct) should suffice.
Demo
$route['techniques/(:any)'] = 'categorysearch/5/$1';
$route['news/(:any)'] = 'categorysearch/1/$1';
This will work I would think!
You shouldn't use a regex for everything - they are not efficient for simple things like this and are designed for more complex scenarios.
The following will do the job (there are better ways but this is easiest to follow!)
$rawstring = "techniques/foo3"
$find = array('techniques', 'news', 'reviews', 'features');
$replace = array('5', '1', '7', '3');
$return = str_replace($find, "categorysearch/" . $replace, $rawstring);
//$return = "categorysearch/5/foo3"
This way also works and is simple to follow for noobies like me :-P Amals answer is far superior!!
Trying to replace a string, but it seems to only match the first occurrence, and if I have another occurrence it doesn't match anything, so I think I need to add some sort of end delimiter?
My code:
$mappings = array(
'fname' => $prospect->forename,
'lname' => $prospect->surname,
'cname' => $prospect->company,
);
foreach($mappings as $key => $mapping) if(empty($mapping)) $mappings[$key] = '$2';
$match = '~{(.*)}(.*?){/.*}$~ise';
$source = 'Hello {fname}Default{/fname} {lname}Last{/lname}';
// $source = 'Hello {fname}Default{/fname}';
$text = preg_replace($match, '$mappings["$1"]', $source);
So if I use the $source that's commented, it matches fine, but if I use the one currently in the code above where there's 2 matches, it doesn't match anything and I get an error:
Message: Undefined index: fname}Default{/fname} {lname
Filename: schedule.php(62) : regexp code
So am I right in saying I need to provide an end delimiter or something?
Thanks,
Christian
Apparently your regexp matches fname}Default{/fname} {lname instead of Default.
As I mentioned here use {(.*?)} instead of {(.*)}.
{ has special meaning in regexps so you should escape it \\{.
And I recommend using preg_replace_callback instead of e modifier (you have more flow control and syntax higlighting and it's impossible to force your program to execute malicious code).
Last mistake you're making is not checking whether the requested index exists. :)
My solution would be:
<?php
class A { // Of course with better class name :)
public $mappings = array(
'fname' => 'Tested'
);
public function callback( $match)
{
if( isset( $this->mappings[$match[1]])){
return $this->mappings[$match[1]];
}
return $match[2];
}
}
$a = new A();
$match = '~\\{([^}]+)\\}(.*?)\\{/\\1\\}~is';
$source = 'Hello {fname}Default{/fname} {lname}Last{/lname}';
echo preg_replace_callback( $match, array($a, 'callback'), $source);
This results into:
[vyktor#grepfruit tmp]$ php stack.php
Hello Tested Last
Your regular expression is anchored to the end of the string so you closing {/whatever} must be the last thing in your string. Also, since your open and closing tags are simply .*, there's nothing in there to make sure they match up. What you want is to make sure that your closing tag matches your opening one - using a backreference like {(.+)}(.*?){/\1} will make sure they're the same.
I'm sure there's other gotchas in there - if you have control over the format of strings you're working with (IE - you're rolling your own templating language), I'd seriously consider moving to a simpler, easier to match format. Since you're not 'saving' the default values, having enclosing tags provides you with no added value but makes the parsing more complicated. Just using $VARNAME would work just as well and be easier to match (\$[A-Z]+), without involving back-references or having to explicitly state you're using non-greedy matching.