PHP: Parse a string to perform replacements - php

I have a group of text based rules that are structured like this:
Rule 1: Do [XXX] when [PN] greater than [N]
Rule 2: Get [PRD ..] and add [X.XX]
To go with this is an array of data that translates each grouped code into a CSS class ID (for jQuery).
I also have an array of translations from [code] to ID stored in a simple structured array, like the following example:
$translate = array(
'XXX' => 'gen-string-input',
'PN' => 'gen-positivenumber-input',
'N' => 'gen-number-input'
);
It is important that the following can be achieved:
I need to replace each instance of [code] with a span tag that is structured like this:
<span class="[classname]" unique="[hash]" offset="[offset]">[CODE]</span>
This is assuming that the fields are
classname is the result of the $translate array
hash is an md5 hash that is static for each rule
offset is the position of the field in the string (e.g. in the first example, field [XXX] is at position 0, [PN] at position 1 and so on).
Based on this information, I would expect to achieve the following output for Rule 1:
<p>
Do <span class="gen-string-input"
unique="[md5]"
offset="0">[XXX]</span>
when <span class="gen-positivenumber-input"
unique="[md5]"
offset="1">[PN]</span>
greater than <span class="gen-number-input"
unique="[md5]"
offset="2">[N]</span>
</p>
Any help is greatly appreciated, I am currently using str_replace to try and achieve this but it is just not good enough.

Ok, actually what you need is preg_replace_callback. See the recursive callback examples.

Iterate through the translate array, replacing the keys in the string with the values
$string = '[CODE]';
$translate = array('classname' => 'oddRow', 'hash' => 'abcdef');
foreach($translate AS $key=>$value)
{
$string = str_ireplace('[' . $key . ']', $value, $string);
}

Related

Find with regular expression MongoDB + PHP

I'm trying to do a PHP find over a MongoDB collection using MongoRegex, but I'm not able to make it work. The code is quite easy:
$cursor = $this->collection->find($params)
//$params has this value:
//Array
//(
// [name] => MongoRegex Object
// (
// [regex] => .*victor.*
// [flags] => i
// )
// [login] => MongoRegex Object
// (
// [regex] => .*victor.*
// [flags] => i
// )
//)
This $params array is constructed with this function:
function toRegEx($entryVars=array()){
$regexVars = array();
foreach($entryVars as $var => $value){
$regexVal = html_entity_decode($value);
$regexVars[$var] = new MongoRegex("/.*".$regexVal.".*/i");
}
return $regexVars;
}
For some reason, this query is only returning the values which makes an exact match (i.e. the documents where login or name are exactly "victor"). What I want is that the query returns all the documents where login and/or name contains the word "victor". I'm pretty sure I'm missing something basic, but I'm not being able to find it. Any help is appreciated. Thanks!
I suppose you simply anchored the regexp to the beginning of the subject string (^), try without :
$regexVars[$var] = new MongoRegex("/".$regexVal."/i");
EDIT:
Also, if the print_r dump of the $params array above is accurate, you're probably missing a $or statement somewhere to reflect your conditions. By default, the mongodb query criteria are linked with a "and" logic, so your query will return records matching regexps on both fields only.

PHP : Formatting multiple arrays for database (laravel)

I've got this input form: (Using the blade template engine with Laravel, but the html should be easy to understand from this and ultimately trivial)
{{ Form::text('amount[]', Input::old('amount')) }}
<?php echo Form::select('unit[]',
array(
'whole' => _('whole'),
'ml' => _('milliliter'),
'l' => _('liter'),
'dl' => _('deciliter'),
'mg' => _('milligram'),
'g' => _('gram'),
'kg' => _('kilogram'),
'tsp' => _('teaspoon'),
'tbs' => _('tablespoon'),
)) ?>
{{ Form::text('ingredient[]', Input::old('ingredient')) }}
I'm trying to format this to my database to return it in a string like this :
<li><span>1</span> liter red wine</li>
I'm considering making it a simpler form and eliminating the unit measurement forcing my users to type it in instead for flexibility, but I'll still have to cramp it all into one table for my database. The span tag is used in a jQuery to dynamically increase the number so is needed. I've been at this for quite a few days on and off but I can't crack how to do this.
Here is my formatting logic:
$amount = Input::get('amount[]');
$unit = Input::get('unit[]');
$ingredient = Input::get('ingredient[]');
for ( $i = 0, $c = count(Input::get('ingredient[]')); $i < $c; $i++ )
{
$ingredients .= '<li><span>'.$amount[$i].'</span>'.$unit[$i].' '.$ingredient[$i].'</li>';
}
and I send it using
$new = Recipe::create(array(
'title' => Input::get('title'),
'curiousity' => Input::get('curiousity'),
'ingredients' => $ingredients,
'steps' => Input::get('recipe')
));
I've tried numerous ways and I get errors like the $ingredients array not being defined or not being able to use [] in the variable. I tried defining the variable as an '$ingredients = '';' variable but that just produced an empty string. My problem must be in the logic.
Build your select list outside the form for brevity as well as (what I do anyway to keep controllers very slim) send the input to the model all at once.
$input = Input::all();
$new = Recipe::create($input);
Build the array for the ingredients elsewhere. In the model (perhaps?):
$ingredients = array(
'dbname1' => 'displayname1',
'dbname2' => 'displayname2'
);
And display it accordingly, then the form inputs should be sent over with the $input in an array that you can parse and then save to your db.
Other notes about Blade syntax. I'm not aware of a need to define the array brackets [].
{{Form::open()}}
{{Form::label('label1','Display Label 1')}}
{{Form::text('fieldname1',Input::old('fieldname1'))}}
With your ingredients array already built (your current syntax will produce a dropdown and I assume you want checkboxes)
{{Form::select('ingredientsFIELDNAME',$ingredients)}}
{{Form::close()}}
In your Input::all() array your ingredientsFIELDNAME field name will have an array if you've built it as checkbox instead of select. Hope this all makes sense.

Regular Expression filtering all translation functions

I am working on a Webinterface that provides the same function like poEdit.
I want to walk trough all .php files in a specified folder and search every line for a translation. For this I would like to use regular expression searching the actual line in the php file and return the translation-text-parameter and the domain-parameter.
My function looks like this:
__('This is my translation', 'domain');
But because for the domain-parameter I defined a default, the function __() can also be called like this:
__('this is my translation');
Now in PHP i tried to use the Function preg_match_all() but i can't gent my regex together.
Here is an example of a possible line in the script and the output array I would like to receive with the preg_match_all() function:
echo __('Hello World'); echo __('Some domain specific translation', 'mydomain');
Array output:
Array
(
[0] => Array
(
[0] => Hello World
)
[1] => Array
(
[0] => Some domain specific translation.
[1] => mydomain
)
)
Can anyone help me out with the Regex and the preg_math_all() flags?
Thank you guys.
Something like this should work. Array shift needed, because zero element will always contain full match, there is no flag to exclude it AFAIK.
if(preg_match_all('/__\(\s*\'((?:[^\']|(?<=\\\)\')+)\'(?:\s*,\s*\'((?:[^\']|(?<=\\\)\')+)\')?\s*\)/us', $data, $result)) {
foreach ($result as &$item) {
array_shift($item);
}
unset($item);
var_dump($result);
}
It finds correctly calls like these __('lorem \' ipsum', 'my\'domain'). It would fail on __('lorem \\') though.
The regex you would need for this is considerably complex.
__\(\s*(['"])((?:(?!(?<!\\)\1).)+)\1(?:,\s*(['"])((?:(?!(?<!\\)\3).)+)\3)?\s*\)
Matches would be in groups 2 and 4, for example
__('This is my translation', 'domain');
would produce these groups:
'
This is my translation
'
domain
and this
__('This is my \'translation\'', "domain");
would produce these groups:
'
This is my \'translation\'
"
domain

php string search - grabbing specific urls

I have this string that may contain some urls that I need to grab. For instance, if the user does:
www.youtube ...
or
www.vimeo ...
or
http://www.youtube ...
or
HttP://WwW.viMeo
I need to grab it (until he finds a space perhaps). and store it on a already created array.
The need is to separate the vimeo links from the youtube ones and place each of those on the appropriate video object.
I'm not sure if this is possible, I mean, if the URL coming from the browser could be used to be placed on a predefined video object. If it is, then this is the way to go (so I believe).
If all this is feasible, can I have your help in order to build such a rule?
Thanks in advance
This matches the links you need, and store them in a 2D array by site name:
$video_links = array();
if (preg_match_all("'(http://)?(www[.])?(youtube|vimeo)[^\s]+'is",$str,$n)) {
foreach ($n[3] as $key => $site)
{
$video_links[$site][] = $n[0][$key];
}
}
What does this do?
This match separates 3 + 1 parts of the needed urls in $str, which is your string:
Part 0: the whole match (your video link)
Part 1: http:// (optional)
Part 2: www. (optional)
Part 3: vimeo or youtube
preg_match_all returns a 2D array with the above part numbers at first level, and every match inside is the part of each match. So you iterate part 3 of the match ($n[3]), and use the array keys to reference part 0 ($n[0][$key]), and arrange them in a nice 2D array like this:
$video_links = array (
'vimeo' => array (
0 => 'vimeo link 1',
1 => 'vimeo link 2',
// ...
),
'youtube' => array (
0 => 'youtube link 1',
1 => 'youtube link 2',
// ...
)
);
What you should do is first replace all instance of http:// and www. with nothing, and then prepend it back on to the string, this makes the string consistent
str_replace(array("http://www.","http://"),"",$url);
$url = "http://" . $url;
then you can use parse_url to check the data like so
$Data = parse_url($url);
Then just check your values accordingly.
switch(strtolower($Data['host']))
{
case "youtube.com":
// :)
break;
case "vimeo.com":
// :)
break;
case "something.tld":
// :)
break;
}
The dump of $Data would output something like so:
[scheme] => http
[host] => youtube.com
[user] =>
[pass] =>
[path] => /watch
[query] => v=r8FVAHuQvjc&feature=topvideos
[fragment] =>
you can now just go
$lastSegment = $Data["path"] . "?" . $Data["query"];
which would return something like /watch?v=r8FVAHuQvjc&feature=topvideos
if you wanted individual items from the query such as the video id you can then go:
parse_str($Data["query"],$result);
echo $result["v"];
which would just output the video id.

How to match numbers in an array in PHP

I am working on the routing or uri's in my PHP app. Currently I have an array with a regex => url map like this...
<?php
$uri_routes = array(
//users/account like http://mysite.com/users/324 (any digit)
'users/friends/page-(\d+)' => 'modules/users/friends/page-$1',
'users/friends/' => 'modules/users/friends/',
'users/online' => 'modules/users/online/' ,
'users/online/page-(\d+)' => 'modules/users/online/page-$1',
'users/create' => 'modules/users/create',
'users/settings' => 'modules/users/settings',
'users/logout(\d+)' => 'modules/users/logout',
'users/login' => 'modules/users/login',
'users/home' => 'modules/users/home',
//forums
'forums/' => 'modules/forums/index',
'forums/viewthread/(\d+)' => 'modules/forums/viewthread/$1',
'forums/viewforum/(\d+)' => 'modules/forums/viewforum/$1',
'forums/viewthread/(\d+)/page-(\d+)' => 'modules/forums/viewthread/$1/page-$2',
'forums/viewforum/(\d+)/page-(\d+)' => 'modules/forums/viewforum/$1/page-$2'
//blog routes coming soon
//mail message routes coming soon
//various other routes coming soon
);
?>
I can then cycle through my $uri_routes map array and match a uri with preg_match() like this...
<?php
//get url from URL
$uri = isset($_GET['uri']) ? $_GET['uri'] : null;
//runs our function and returns an array
// $uri['module'] this will be the class/module/section
// $uri['method'] this will be the page in that section or method in that class
// $uri['urifragments'] this will either page a user ID, or an item ID or a page number for paging
$uri = get_route($_GET['uri'],$uri_routes);
function get_route($uri,$uri_routes)
{
foreach($uri_routes as $rUri => $rRoute)
{
if(preg_match("#^{$rUri}$#Ui",$uri))
{
$uri = preg_replace("#^{$rUri}$#Ui",$rRoute,$uri);
break;
}
}
$uri = explode('/',$uri);
$return['module'] = $uri['1'];
$return['method'] = $uri['2'];
$return['urifragments'] = $uri['3'];
$return['urifragments2'] = $uri['4'];
return $return;
}
I am open to an suggestion to improve this in any way. Right now I am stuck as there is 4 possible array key/values returned. If array key 3 or key 4 contains the word "page-" followed by a number, I would like to assign it to a $page variable. But if key 3 or key 4 contains just a number with no "page-" word, then I can assume it is a user ID, blog ID, forum ID, etc and assign it to an $id variable.
If you know a good approach to this, please help.
UPDATE
to simplify things, in addition to having "page-" in front of page numbers, I could have "id-" in front of id numbers
Instead of using $1 and $2 to match our routes try using named captures.
5.2.2 Named subpatterns now accept the syntax (?) and (?'name') as
well as (?P). Previous versions
accepted only (?P).
Source : preg_match
Also when you are doing a preg_replace you use \[0-99] where \0 is the whole string and \1 through \99 are the matches.
But if you are going to be using named captures you can assign an array to the $replacement parameter with the name capture (e.g. if you capture ?P<page> then you would pass an array('page'=>"new value of page")).
Hope that helps.

Categories