RegEx - extend a given string while leaving the rest untouched - php

I have an associate array inside a PHP class method going like this:
// ...
$filters = [
self::FILTER_CREATION_DATE => "Base/*/Creation/Date.php",
self::FILTER_CREATION_DATE_BETWEEN => "Base/*/Creation/Date.php",
self::FILTER_CREATION_DATE_GREATER => "Base/*/Creation/Date.php",
self::FILTER_CREATION_DATE_GREATER_OR_EQUAL => "Base/*/Creation/Date.php",
self::FILTER_CREATION_DATE_LESS => "Base/*/Creation/Date.php",
self::FILTER_CREATION_DATE_LESS_OR_EQUAL => "Base/*/Creation/Date.php",
];
// ...
What I would like to do is to convert this string from:
self::FILTER_CREATION_DATE_BETWEEN => "Base/*/Creation/Date.php",
to this one:
self::FILTER_CREATION_DATE_BETWEEN => "Base/*/Creation/Date/Between.php",
I would like to use a RegEx to extend the string but leave the rest untouched. I need to do this because there's more than 120 constants defined ending with *_BETWEEN.
How can I do this?

In the Intellij editor or the free Notepad++, you can find and replace by regex.
I'm sure other IDE's have similar functionality
Find self::([_A-Z]+)_BETWEEN => "(.*)/Date.php"(,)*
Replace self::$1_BETWEEN => "$2/Date/Between.php"$3
The regex groups the variable components of your search together by wrapping it in ()
In the replace you can reference them in order by $1, $2, etc..

Related

Passing a stdclass compact array to new Lang_String in Moodle plugin lanaguage file?

I'm trying to pass a stdclass (containing array of measurement and name details) using a new Lang_String in Moodle plugin code:
redirect(new moodle_url('/mod/healthtracker/profile_measurements.php', ['id' => $userMeasurement->userid, 'course' => $userMeasurement->courseid]), new lang_string('delete_patient_measurement_success', 'mod_healthtracker', (object)compact('user','measurement')), \core\output\notification::NOTIFY_SUCCESS);
the lang sting itself being:
'delete_patient_measurement_success' => 'The {$a->measurement->name} measurement has been removed from {$a->user->firstname} {$a->user->lastname}',
however at present the output is:
The {$a->measurement->name} measurement has been removed from {$a->user->firstname} {$a->user->lastname}
whereas I actually want the lang string to display the variable values e.g. 'Blood Pressure' in place of {$a->measurement->name} and 'Bob' in place of {$a->user->firstname}
I think the (object)compact('user','measurement')) is the issue here but is not sure where the syntax is incorrect - any help greatfully received!
Moodle language strings only support single depth objects for substitutions.
So, a valid language string would look like this:
$string['delete_patient_measurement_success'] = "The {$a->measurementname} measurement has been removed from {$a->firstname} {$a->lastname}";
You would then call use it like this:
$str = new lang_string('delete_patient_measurement_success', 'mod_healthtracker', (object)[
'measurementname' => $measurement->name,
'firstname' => $user->firstname,
'lastname' => $user->lastname,
]);

Put string content into array php

I have this string
string(2091) "
"roots" => array(
array(
"driver" => "LocalFileSystem", // driver for accessing file system (REQUIRED)
"path" => "../files/", // path to files (REQUIRED)
//"URL" => dirname($_SERVER["PHP_SELF"]) . "/../files/", // URL to files (REQUIRED)
"accessControl" => "access" , // disable and hide dot starting files (OPTIONAL)
"alias" => "Root",
//"uploadDeny" => array("all"),
"attributes" => array(
array(
"pattern" => "/\manuali$/", //You can also set permissions for file types by adding, for example, <b>.jpg</b> inside pattern.
// "pattern" =>"/\PROVA$/",
"read" => true,
"write" => false,
"locked" => true,
),
array(
"pattern" => "/rapporti$/", //You can also set permissions for file types by adding, for example, <b>.jpg</b> inside pattern.
// "pattern" =>"/\PROVA$/",
"read" => true,
"write" => true,
"locked" => true,
)
[...]
";
i want to put into array the entire value of a string. Ex:
array(
"roots" => array(
array(
"driver" => "LocalFileSystem", // driver for accessing file system (REQUIRED)
"path" => "../files/", // path to files (REQUIRED)
//"URL" => dirname($_SERVER["PHP_SELF"]) . "/../files/", // URL to files (REQUIRED)
"accessControl" => "access" , // disable and hide dot starting files (OPTIONAL)
"alias" => "Root",
//"uploadDeny" => array("all"),
"attributes" => array(
array(
"pattern" => "/\manuali$/", //You can also set permissions for file types by adding, for example, <b>.jpg</b> inside pattern.
// "pattern" =>"/\PROVA$/",
"read" => true,
"write" => false,
"locked" => true,
),
array(
"pattern" => "/rapporti$/", //You can also set permissions for file types by adding, for example, <b>.jpg</b> inside pattern.
// "pattern" =>"/\PROVA$/",
"read" => true,
"write" => true,
"locked" => true,
)
[...]
);
i have tried str_split() implode() array_push()... but every function put the string into array in this mode array(string(" "))i want to put in this mode array(" ").
Thanks
If your string is parseable and you don't mind about possible injections, you can simply eval your array representation.
For example, if your string is in $arrayStr and you want to create an array $myArray from that:
$arrayStr = '"roots" => array ( ... )';
eval('$myArray = array(' . $arrayStr . ');');
Note that if $arrayStr is not entirely controller by you from generation to conversion, it is highly risky since anything in it would be evaluated.
A better solution to exchange a whole array between parts of your application would be to serialize() it beforehand to create a string representation of your array/object which can be stored, and then unserialize it when you need it in its original form.
There's two main methods I can think of.
One, is to use some sort of complex pattern matching loop using preg_match. You can split the string into each line by using explode and \n to convert it into an array (of each line), loop through each row, and use pattern matching (regex) to figure out what to do with it.
The second method is incredibly dangerous, so I highly advise you to not use it, but php has it's own eval function which would let PHP interpret the string as actual PHP.
You would need to append a variable assignment inside the string e.g.
$arrayString = "$var = array(' . $arrayString . ');";
And then
eval($arrayString);
However, you really don't want to be doing this if you can. From the PHP docs:
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.

Zend route regex, optional parameters

I need some help about my routes in Zend (Zend1) ...
I need that I can use my route like that :
http://mywebsite.com/myfolder/region/job/
http://mywebsite.com/myfolder/region/job/add
http://mywebsite.com/myfolder/region/job/add/page
http://mywebsite.com/myfolder/region/job/page
Parameters add and page are optional ...
This is what I did
$route = new Zend_Controller_Router_Route_Regex(
'myfolder/([^/]+)/([^/]+)/?([^/]+)?/?([0-9]+)?',
array('controller' => 'myfolder','action' => 'search'),
array(1 => 'region',2 => 'job', 3 => 'add', 4 => 'page'),
'myfolder/%s/%s/%s/%s'
);
Obviously, it doesn't work ...
What I want? I want that last the two parameters (add and page) are optional ...
Can you help me? what's wrong with my regex?
EDIT 1:
Ok, so I tried it, but isn't ok ...
I need that parameters add and page are optional ...
$route = new Zend_Controller_Router_Route(
'myfolder/:region/:job/:add/:page',
array(
'controller' => 'myfolder',
'action' => 'search',
'region' => 'XX',
'job' => '',
'add' => '',
'page' => 1
),
array(
'region' => '[a-zA-Z-_0-9-]+',
'job' => '[a-zA-Z-_0-9-]+',
'add' => '[a-zA-Z-_]+',
'page' => '\d+'
)
);
With that, this one http://mywebsite.com/myfolder/region/job/page doesn't work ...
EDIT 2:
I also tried with 'myfolder/:region/:job/*', but the result is same, doesn't work as I want ...
I really wonder if it is possible ...
EDIT 3:##
$route = new Zend_Controller_Router_Route_Regex('myfolder/([^/]+)/([^/]+)(?:/|$)(?:(?!\d+(?:/|$))([^/]+)(?:/|$))?(?:(\d+)(?:/|$))?$',
array('controller' => 'myfolder', 'action' => 'recherche', 'presta' => ''),
array(1 => 'region',2 => 'job', 3 => 'presta', 4 => 'page'),
'myfolder/%s/%s/%s/%s');
Prepare yourself.
The RegEx
myfolder/([^/]+)/([^/]+)(?:/|$)(?:(?!\d+(?:/|$))([^/]+)(?:/|$))?(?:(\d+)(?:/|$))?$
See it working on RegExr (on RegExr, I had to add \n\r to one of the negated classes so it didn't match all my line breaks, in practice you probably won't be dealing with line breaks though.)
The important thing to note on RegExr is that in the 4th case, the page number is in the 4th capture group, with nothing in the 3rd group.
Explanation
myfolder/([^/]+)/([^/]+) All looking good up to here, no changes yet.
(?:/|$) Match a / or end of input.
Next, overall we have a non-capturing group that is optional. This would be the add section.
(?:(?!\d+(?:\|$))([^/]+)(?:/|$))?
Now lets break it down further:
(?!\d+(?:/|$)) Make sure its not a page number - digits only followed by / or end of input. (Negative lookahead)
([^/]+) Our capture group - add in the example.
(?:/|$) Match a / or end of input.
Now for our page number group, again it's optional and non-capturing:
(?:(\d+)(?:/|$))? Captures the numbers, then matches / or end of input again.
$ And just in case it tries to match substrings of actual matches, I threw in another end of input anchor (since you can match as many in a row as you like), although the regex functions without it.
Generating The Path
What you basically want is a way of doing this:
At the moment the 2nd and 3rd parameters are:
array(1 => 'region',2 => 'job', 3 => 'add', 4 => 'page'),
'myfolder/%s/%s/%s/%s'
You want them to be something like:
array(1 => 'region',2 => 'job', 3 => '/'+'add', 4 => '/'+'page'),
'myfolder/%s/%s%s%s'
Where you only add the / if the optional group is present. The code above won't work but perhaps there is some way you could implement that.

REGEX to parse template echo

I'm trying to parse some input using regex. The input will be in the format:
{somevalue:3}
The aim is to display 'som' (no quotemarks).
At the moment, I have:
'echo' => array(
'search' => '~\{((?:'.$this->preg['var'].')(?:\.)?)\}~sU',
'replace' => "'.\$this->_get('\\1').'"
)
Which works great with my template system, to echo the standard variable (i.e. 'somevalue'). However, I wish to allow the user to use the : delimiter to limit the number of characters to output (i.e. {somevalue:3} would display 'som').
I tried:
'echo' => array(
'search' => '~\{((?:'.$this->preg['var'].')(?:\.)?:(.*)/)\}~sU',
'replace' => "'.substr(\$this->_get('\\1'),0,\\2).'"
)
But this didn't work. I don't really understand regex to be honest so any help would be much appreciated.
It looks like you have an extra '/' in the new search expression.
|
v
'search' => '~\{((?:'.$this->preg['var'].')(?:\.)?:(.*)/)\}~sU',
I'm not familiar with the templating system you're using, but it appears that the replace expression would need to be changed as well.
'replace' => "'.substr(\$this->_get('\\1'),0,\$this->_get('\\2')).'"
Put these together and you'd get something like this to try:
'echo' => array(
'search' => '~\{((?:'.$this->preg['var'].')(?:\.)?:(.*))\}~sU',
'replace' => "'.substr(\$this->_get('\\1'),0,\$this->_get('\\2')).'"
)
It should be noted that if this works, the old way of doing input won't work anymore. In other words, you'll always have to use the format {<string>:<num_of_chars>} and not just {<string>}.
$s = preg_replace_callback(
'/\{([^:]+):(\d+)\}/',
create_function('$m', 'return substr($m[1], 0, $m[2]);'), $s);
Test this code here.

Using multiple PregReplace filters on a Zend Form element

I want to be able to add multiple PregReplace filters on a single Zend Form element.
I can add one PregReplace filter using the code below:
$word = new Zend_Form_Element_Text('word');
$word->addFilter('PregReplace', array(
'match' => '/bob/',
'replace' => 'john'
));
$this->addElement($word);
I've tried
$word = new Zend_Form_Element_Text('word');
$word->addFilter('PregReplace', array(
'match' => '/bob/',
'replace' => 'john'
));
$word->addFilter('PregReplace', array(
'match' => '/sam/',
'replace' => 'dave'
));
$this->addElement($word);
but this just meant only the second filter worked.
How do I add multiple PregReplace filters?
The problem you're facing is that the second filter will override the first one in the filters stack ($this->_filters) defined in Zend_Form_Element.
As David mentioned in the question comments, the filters stack use filter names as index ($this->_filters[$name] = $filter;) this is the reason why the second filter override the first one.
In order to resolve this problem, you can use a custom filter as follows:
$element->addFilter('callback', function($v) { return preg_replace(array('/bob/', '/sam/'),array('john', 'dave'), $v); });
This is done using an inline function(), in case you're not using PHP version 5.3 or higher, you can set your callback as follows to make it work:
$element->addFilter('callback', array('callback' => array($this, 'funcName')));
And add under your init() method in your form:
function funcName($v) {
return preg_replace(array('/bob/', '/sam/'), array('john', 'dave'), $v);
}
At last, if you want to use only the PregReplace filter, unlike Marcin's answer (the syntax is incorrect), you can still do it this way:
$element->addFilter('pregReplace', array(
array('match' => array('/bob/', '/sam/'),
'replace' => array('john', 'dave')
)));
That should do the trick ;)
Since PregReplace uses php's preg_replace function, I guess something like this would be possible (preg_replace can accepts arrays of patterns and array of corresponding replacement strings):
$word = new Zend_Form_Element_Text('word');
$word->addFilter('PregReplace', array(
'match' => array('/bob/', '/sam/'),
'replace' => array('john' , dave)
));
$this->addElement($word);
I haven't tested it though. Hope it will work.
I was unable to get the previous example to work with 'PregReplace'. I switched instead to calling it with new Zend_Filter_PregReplace(). It now works for me.
$word->addFilter(new Zend_Filter_PregReplace(array(
'match' => array('/bob/', '/sam/'),
'replace'=> array('john', 'dave'))
));
I was looking for same-response does not have a usable version
$word->addFilter(new Zend_Filter_PregReplace(new Zend_Config(array(
'match'=>array('/bob/', '/sam/'),
'replace'=>array('john', 'dave')
))));

Categories