|
 |
preg_replace_callback (PHP 4 >= 4.0.5, PHP 5) preg_replace_callback -- Выполняет поиск по регулярному выражению и замену с использованием функции обратного вызова Описаниеmixed preg_replace_callback ( mixed pattern, callback callback, mixed subject [, int limit] )
Поведение этой функции во многом напоминает
preg_replace(), за исключением того, что вместо
параметра replacement необходимо указывать
callback функцию, которой в качестве
входящего параметра передается массив найденных вхождений.
Ожидаемый результат - строка, которой будет произведена замена.
Пример 1. preg_replace_callback() пример
<?php
$text = "April fools day is 04/01/2002\n";
$text.= "Last christmas was 12/24/2001\n";
function next_year($matches)
{
return $matches[1].($matches[2]+1);
}
echo preg_replace_callback(
"|(\d{2}/\d{2}/)(\d{4})|",
"next_year",
$text);
?>
|
|
Достаточно часто callback функция, кроме как в вызове
preg_replace_callback(), ни в чем больше не участвует.
Исходя из этих соображений, можно использовать create_function()
для создания безымянной функции обратного вызова непосредственно
в вызове preg_replace_callback().
Если вы используете такой подход, вся информация, связанная с заменой по
регулярному выражению, будет собрана в одном месте, и пространство имен
функций не будет загромождаться неиспользуемыми записями.
Пример 2. preg_replace_callback() и create_function()
<?php
$fp = fopen("php://stdin", "r") or die("can't read stdin");
while (!feof($fp)) {
$line = fgets($fp);
$line = preg_replace_callback(
'|<p>\s*\w|',
create_function(
'$matches',
'return strtolower($matches[0]);'
),
$line
);
echo $line;
}
fclose($fp);
?>
|
|
Смотрите также preg_replace() и
create_function().
preg_replace_callback
matt at mattsoft dot net
26-Apr-2006 02:16
it is much better on preformance and better practice to use the preg_replace_callback function instead of preg_replace with the e modifier.
function a($text){return($text);}
// 2.76 seconds to run 50000 times
preg_replace("/\{(.*?)\}/e","a('\\1','\\2','\\3',\$b)",$a);
// 0.97 seconds to run 50000 times
preg_replace_callback("/\{(.*?)\}/s","a",$a);
mplescano at gmail dot com
05-Mar-2006 10:12
class User {
var $id;
var $usuario;
var $clave;
function setId ($id) {
$this->id = $id;
}
function getId () {
return $this->id;
}
function setUsuario ($usuario) {
$this->usuario = $usuario;
}
function getUsuario () {
return $this->usuario;
}
function setClave ($clave) {
$this->clave = $clave;
}
function getClave () {
return $this->clave;
}
function User () {
}
}
class PropertyUtils
{
...
/**
* Get the value of the specified property on the subject bean using
* the standard notation for getter methods from the JavaBean spec.
*
* @return Object
*/
function &getSimpleProperty(&$bean, $name)
{
if (is_null($bean)) {
return null;
}
$method = 'get' . ucfirst($name);
if (!method_exists($bean, $method)) {
$method = 'is' . ucfirst($name);
}
if (!method_exists($bean, $method)) {
$method = null;
}
if (is_null($method)) {
return null;
}
$return =& $bean->$method();
return $return;
}
...
}
$statement['user.insert'][] = array('sentence'=>"INSERT INTO tb01 (id, usuario, clave) VALUES (#id#, #usuario#, #clave#)", 'parameter'=>'User');
class Mapper {
...
function insert ($clazzName, $newBean, $order = 0) {
global $statement;
$statementStr = $statement[$clazzName.'.'.'insert'][$order]['sentence'];
if (get_class($newBean) !== false && $clazzName == get_class($newBean)) {
$statementParsed = Mapper::parseStatementBeanParameter($newBean, $statementStr);
}
else if (is_array($newBean) && count($newBean) > 0) {
$statementParsed = Mapper::parseStatementArrayParameter($newBean, $statementStr);
}
return $statementParsed;
}
...
function parseStatementBeanParameter (&$bean, $statement) {
$parsedStatement = preg_replace("/#([^#\s]+)#/e","Mapper::searchParameterBean('\\1', \$bean)", $statement);
return $parsedStatement;
}
...
function searchParameterBean ($index, $bean) {
$clazzName = get_class($bean);
$propertyValue = '';
if (!($clazzName == '' || $clazzName === false)) {
$propertyValue = PropertyUtils::getSimpleProperty($bean, $index);
}
return $propertyValue;
}
}
$user =& new User();
$user->setId(1);
$user->setUsuario("antonio");
$user->setClave("aguiero");
echo Mapper::insert (get_class($user), $user);
Print:
INSERT INTO tb01 (id, usuario, clave) VALUES (1, antonio, aguiero)
06-Jan-2006 11:55
I've found php will crash when I store a reference to the $match parameter but there's an easy work around...
$mylist=array();
function my_callback($match) {
global $mylist;
// this crashes PHP...
// $mylist[]=$match;
// this copies the $match array so is safe
$mylist[]=array_merge($match);
return 1;
}
$subject="The rain in Spain falls mainly on the plane.";
echo "<p>".preg_replace_callback("/[aeiou]/i", "my_callback", $subject);
echo "<p>"; print_r($mylist);
user at lesplumesdusavoir dot net
31-Oct-2005 02:39
You can use this method instead of preg_replace_callback :
<?php
echo preg_replace("`(<\/?)(\w+)([^>]*>)`e", "html_body('\\1', '\\2', '\\3', \$extra_info)", $html_body); ?>
It works very well. Enjoy :)
admin at the-php-tree dot com
27-Jun-2005 04:15
Instead of using preg_replace_callback() you could use preg_replace() like below:
<?php
function my_function( $my_param_one, $my_param_two ) {
}
preg_replace( "! \{(.+)-(.+)\} !e", "my_function('\\1', '\\2')", $input_string );
class my_class {
function my_class() {
preg_replace( "! \{(.+)-(.+)\} !e", "\$this->my_function('\\1', '\\2')", $input_string );
}
function my_function( $my_param_one, $my_param_two ) {
}
}
?>
larry at fantasyclub dot ru
02-May-2005 09:08
A powerful php template parser may be written in one line of code :)
(Of course there are many ways of it, this is my own just developed)
print preg_replace_callback("/<\\?(.*?)\\?>/",
create_function('$m','extract($GLOBALS);
return(eval("return($m[1]);"));'),$s);
Template example:
<?$var["x1"]?><br>
<?$var["x2"]?><br>
<?$var["x1"]." php foreva ".$var["x2"]?><br>
So, as you can see, <? and ?> are template parser tags and it is even possible to make simple php expressions inside such tags. However not too complex to confuse designer :)
You may add \" around inner $m[1] at your taste and templates will be little different ;)
Another advantage of such parser that you do not need to worry about variables must be available in templates - all globals and global arrays will be :) Very handy in fact.
As I saw above, this can be optimized by making separate (not inline) callback function, and I will of courde do it in real program, but this is less gracefull than I wrote here :)
Jari Pennanen
10-Dec-2004 10:03
It is not typo, notice the "e" at the end of the pattern, it does the job.
But there is typo in another place, in class example there is one extra \\ before $this word.
23-Aug-2004 07:05
There is a small typo with the code (at least when I try to implement it) in the first comment.
<?php
echo preg_replace("/(<\/?)(\w+)([^>]*>)/e", "html_body('\\1', '\\2', '\\3', '$extra_info')", $html_body);
?>
should really be
<?php
echo preg_replace("/(<\/?)(\w+)([^>]*>)/e", html_body('\\1', '\\2', '\\3', '$extra_info'), $html_body);
?>
That is, the second argument should not have quotes around it. This should apply to all of the other examples in the comments as well.
18-Aug-2004 07:00
if you want to send some extra parameters to your call back function here's how to do it (using preg_replace instead!). i took the example from the manual, on how to convert html tags to upper case...
if you don't use a class:
<?php
$extra_info = "some extra info";
echo preg_replace("/(<\/?)(\w+)([^>]*>)/e", "html_body('\\1', '\\2', '\\3', '$extra_info')", $html_body);
function html_body($open_tag, $the_tag, $close_tag, $extra_info) {
return $before . strtoupper($middle) . $after;
}
?>
class example:
<?php
class SomeClass {
function SomeClass() {
$extra_info = "some extra info";
echo preg_replace("/(<\/?)(\w+)([^>]*>)/e", "\\$this->html_body('\\1', '\\2', '\\3', '$extra_info')", $html_body);
}
function html_body($open_tag, $the_tag, $close_tag, $extra_info) {
return $before . strtoupper($middle) . $after;
}
}
?>
now, if you'd like to pass an array :)
<?php
$extra_info = ("some extra info", "little more", "a bit more");
echo preg_replace("/(<\/?)(\w+)([^>]*>)/e", "html_body('\\1', '\\2', '\\3', \\$extra_info)", $html_body);
function html_body($open_tag, $the_tag, $close_tag, $extra_info) {
return $before . strtoupper($middle) . $after;
}
?>
you can also pass the array as a reference...cool!
hope this helps someone! ;)
ply at ukrpost dot net
16-Jun-2004 03:11
Example given for preg_replace_callback with create_function have one flow - it consume a lot of memory. Each call to create_function allocate some memory to create a new function, and to the end of the script a lot of memory could be consumed, if there are many lines recieved from stdin. Of course after ending all memory will be freed, but I have been hanged up my computer processing 20Mb file with similar code on Windows.
<?php
$fp = fopen("php://stdin", "r") or die("can't read stdin");
while (!feof($fp)) {
$line = fgets($fp);
$line = preg_replace_callback('|<p>\s*\w|',
create_function(
'$matches',
'return strtolower($matches[0]);'
),
$line
);
echo $line;
}
fclose($fp);
?>
ben at benchun dot net
18-Mar-2004 08:19
a repost (with correction) of a note originally attributed to matthew at de-construct dot com (26-Aug-2003 04:48) - a note i found in a compiled help file but which i do not see on this site. he was missing a stripslashes call in his example, which i have fixed below:
<?
$outer_data = array('foo'=>'abc','bar'=>'123');
$callback = create_function('$matches',
'
$inner_data = unserialize(stripslashes("'. addslashes(serialize($outer_data)) .'"));
// do something here
return $inner_data[$matches[1]];
'
);
$template_data = preg_replace_callback("/\{[$](.*?)\}/", $callback, $template_data);
?>
i found this very useful for implementing a template engine!
spamhoneypot at acksys dot co dot uk
16-Dec-2003 06:08
I thought I'd post this as I'd been using the function preg_replace_callback with NP within functions, but as soon as I re-wrote my script as a class, it all fell apart.
When debugging I ended up writing test code and this is what follows. It works as I'd expect, YMMV of course.
<?php
class foo
{
function parse()
{
$pattern = "/<a(.*?)href\s*=\s*['|\"|\s*](.*?)['|\"|>](.*?)>(.*?)<\/a>/i";
$string = "<a class='whatever' href='http://foo.com' target='_blank'>foo</a>";
print preg_replace_callback($pattern,array($this,'cb'),$string);
}
function cb($matches)
{
return "<a" . $matches[1] . "href='http://someothersite.com/foo.php?page=" . urlencode($matches[2]) . "'" . $matches[3] . ">" . $matches[4] . "</a>";
}
}
$bar = new foo();
$bar->parse();
?>
vlad4321 at fastmail dot fm
11-Nov-2003 03:47
You can use this function to display url address as a link or image based on suffix of the url.
Every string beginning with www or http(s):// will be displayed as an URL address. But if the string ends with *.jpg or *.gif, it will be displayed as an image.
Please note: This function also verifies the size of the image. If is it more than 600x400, it changes it.
<?php
$pattern_html = "/\b((http(s?):\/\/)|(www\.))([\w\.]+)";
$pattern_html .= "([\#\,\/\~\?\&\=\;\%\-\w+\.]+)\b/i";
$text = preg_replace_callback($pattern_html,'Check_if_Image',$text);
.
.
function Check_if_Image($matches) {
$suffix = strtolower(substr($matches[0],-4));
if ( $suffix == '.jpg' or $suffix == '.gif') {
$dsn = 'http'.$matches[3].'://'.$matches[4].$matches[5];
if (list($width, $height, $type, $attr) = getimagesize("$dsn")) {
if ( ($width > 600) ) {
$koef = $width / 600;
$width = 600;
$height /= $koef;
}
if ( ($height > 400) ) {
$koef = $height / 400;
$height = 400;
$width /= $koef;
}
}
else {
$height=400;
$width=600;
}
$ret = "<img src=\"$dsn\"";
$ret .= "\" border=0 width=\"$width\" height=\"$height\">";
}
else {
$ret = '<a href="http'.$matches[3].'://'.$matches[4].$matches[5];
$ret .='" target="_blank">'.$matches[0].'</a>';
}
return ("$ret");
}
?>
27-Oct-2003 11:05
Here's an example of how to evaluate PHP code inside a HTML block. In my example I have two timestamps which I insert at several places in a HTML-template. The formatting for the dates are put inside the template. When the insert is done the code is evaluated and the dates are formatted. All code inside "<php>" to "</php>"-tags will be evaluated.
-----------------------------------------------------------
function evalcode($matches)
{
eval("\\$matches[2] = $matches[2];");
return $matches[2];
}
$template = "<html><body>This really simple HTML-page that was created at <php>date('Y-m-d',{datecreated})</php> and modified at <php>date('H:i:s',{datemodified})</php> on the <php>date('dS',{datemodified})</php> of <php>date('F Y',{datemodified})</php>.</body></html>";
$datecreated = 1065162746;
$datemodified = time();
$output = $template;
$output = str_replace('{datecreated}', $datecreated, $output);
$output = str_replace('{datemodified}', $datemodified, $output);
$output = preg_replace_callback("/(<php>)(.*)(<\\/php>)/U", "evalcode", $output);
echo $output;
----------------------------------------------------------
The output will be something like "This really simple HTML-page that was created at 2003-10-03 and modified at 16:58:31 on the 27th of October 2003."
e-mail at dreamguard dot at
23-Oct-2003 02:02
If you want to do a date function in a template system you'll have to use the callback here.
Ex.:
function date_match ($matches)
{
return date ($matches['2']);
}
$output = preg_replace_callback ('/({DATE=")(.{1,})("})/', 'date_match', $input);
hans at velum dot net
01-Aug-2003 07:31
Also, if you want to use a *static* class method for the callback function, you can refer to it like this:
preg_replace_callback(pattern, array('ClassName', 'methodName'), subject)
In PHP5, from within the class:
preg_replace_callback(pattern, array('self', 'methodName'), subject)
nospam at hirnbrand dot de
16-Oct-2002 11:58
if you want to pass the callback function more parameters than just match parts, use the e-modifier in preg_replace instead of preg_replace_callback
oyoryelNOSPAM at hotNOSPAMmail dot com
21-Apr-2002 09:23
If you want to be able to change variables of the class in the callback function, you have to use preg_replace_callback(pattern, array(&$this, 'method_name'), subject)
Probably very obvious, but it kept me busy for a while...
| |