I need to convert preg_replace() to preg_replace_callback() in this function of an outdated CMS extension:
// santizes a regex pattern
private static function sanitize( $pattern, $m = false, $e = false ) {
if( preg_match( '/^\/(.*)([^\\\\])\/(.*?)$/', $pattern, $matches ) ) {
$pat = preg_replace(
'/([^\\\\])?\(\?(.*\:)?(.*)\)/Ue',
'\'$1(?\' . self::cleanupInternal(\'$2\') . \'$3)\'',
$matches[1] . $matches[2]
);
$ret = '/' . $pat . '/';
if( $m ) {
$mod = '';
foreach( self::$modifiers as $val ) {
if( strpos( $matches[3], $val ) !== false ) {
$mod .= $val;
}
}
if( !$e ) {
$mod = str_replace( 'e', '', $mod );
}
$ret .= $mod;
}
} else {
$pat = preg_replace(
'/([^\\\\])?\(\?(.*\:)?(.*)\)/Ue',
'\'$1(?\' . self::cleanupInternal(\'$2\') . \'$3)\'',
$pattern
);
$pat = preg_replace( '!([^\\\\])/!', '$1\\/', $pat );
$ret = '/' . $pat . '/';
}
return $ret;
}
I can only imagine what this function does. I tried this but it didsn't work:
private static function sanitize( $pattern, $m = false, $e = false ) {
if( preg_match( '/^\/(.*)([^\\\\])\/(.*?)$/', $pattern, $matches ) ) {
$pat = preg_replace_callback(
'/([^\\\\])?\(\?(.*\:)?(.*)\)/U',
function($matches) {return CallFunction('\'$1(?\' . self::cleanupInternal(\'$2\') . \'$3)\''); },
$matches[1] . $matches[2]
);
$ret = '/' . $pat . '/';
if( $m ) {
$mod = '';
foreach( self::$modifiers as $val ) {
if( strpos( $matches[3], $val ) !== false ) {
$mod .= $val;
}
}
if( !$e ) {
$mod = str_replace( 'e', '', $mod );
}
$ret .= $mod;
}
} else {
$pat = preg_replace_callback(
'/([^\\\\])?\(\?(.*\:)?(.*)\)/U',
function($matches) {return CallFunction('\'$1(?\' . self::cleanupInternal(\'$2\') . \'$3)\''); },
$pattern
);
$pat = preg_replace( '!([^\\\\])/!', '$1\\/', $pat );
$ret = '/' . $pat . '/';
}
return $ret;
}
Could somebody help me on this?
Without any certitude, you can try this for the first preg_replace, and modify the second preg_replace in a same way:
$that = $this;
$pat = preg_replace_callback(
'/([^\\\\])?\(\?(.*:)?(.*)\)/U',
function ($m) use ($that) {
return $m[1] . '(?' . $that->cleanupInternal($m[2]) . $m[3];
},
$matches[1] . $matches[2]
);
As an aside comment, I don't think that ([^\\\\])? has any sense or is useful for something since it is optional and reuse in the replacement string at the same position.
Related
The first line of code is converted to the second code. I can use the padding methods, but I want to get the solution from the shortest path and convert it quickly. I will use the code field in the sql select section
$it = "(a(am,bam),b(dam,cam))";
$to = "a.am, a.bam, b.dam, b.cam";
Try following code:
$it = "(a(am,bam),b(dam,cam))";
function iDelimiter( $str ) {
$count = 0;
$str = str_split( $str );
foreach( $str as &$value ) {
if( $value == "(" ) {
$count++;
} elseif( $value == ")" ) {
$count--;
}
if( $value == "," && ! $count ) {
$value = "|";
}
}
return explode( "|", implode( $str ) );
}
function iParser( $str, $_prefix = "" ) {
preg_match( "/^((?!(\(|\))).)*\((.*)\)$/", $str, $m );
if( count( $m ) < 4 ) {
return ( strlen( $_prefix ) ? $_prefix . "." : '' ) . $str;
}
$prefix = ( strlen( $_prefix ) ? $_prefix . "." : '' ) . $m[1];
$str = $m[3];
if( strpos( $str, "(" ) === false ) {
$return = explode( ",", $str );
$pad = preg_filter( '/^/', strlen( $prefix ) ? $prefix . '.' : '', $return );
return implode( $pad, "," );
} else {
$str = iDelimiter( $str );
$return = array_map( 'iParser', $str, array_pad( array(), count( $str ), $prefix ) );
return implode( $return, ", " );
}
}
print_r( iParser( $it ) );
It parse every depth of parentheses. Just pass your string to iParser function.
Try this:
<?php
function str2Arr( $s, $r, $str) {
$str = trim( str_replace( $s, $r, $str ));
return explode(" ", $str);
}
$it = "(a(am,bam),b(dam,cam))";
//$to = "a.am, a.bam, b.dam, b.cam";
$search = ['),', '(', ')', ',', 'a a', 'b d', 'ba', 'c'];
$replace =[' ', ' ', ' ', ' ', 'a.a','b.d', 'a.ba', 'b.c'];
var_dump( implode(", ",( str2Arr( $search, $replace, $it) ) ) );
See demo
Without using a regex one may achieve the specified conversion by using str_replace() which uses an array of characters to be replaced by another array of characters when found in the subject string. The non-alphabetical characters are each replaced with blank space and the substrings are replaced so that each starts with an "a" or "b" as appropriate followed by a period and the rest of the substring.
Kill me now. There's got to be a better way, but my eyes are bleeding.
It probably would have worked much better had I started with a regex, but my regex skills are rusty.
I kept pounding your data with a hammer until the square peg went through the round hole.
<?php
$it = "(a(am,bam),b(dam,cam))";
$it = substr($it, 1, -1);
//$to = "a.am, a.bam, b.dam, b.cam";
$final = [];
$test = explode("),", $it);
foreach($test as $section) {
$letter = substr($section, 0, 1);
$remainder = substr($section, 2);
if(strpos($remainder, ")")) {
$remainder = substr($remainder, 0, strpos($remainder, ")"));
}
echo $letter . " ".$remainder."\n";
foreach(explode(",", $remainder) as $fragment) {
array_push($final, $letter.".".$fragment);
}
}
var_dump($final);
var_dump(implode($final, ", "));
Yields
a am,bam
b dam,cam
array(4) {
[0]=>
string(4) "a.am"
[1]=>
string(5) "a.bam"
[2]=>
string(5) "b.dam"
[3]=>
string(5) "b.cam"
}
string(22) "a.am, a.bam, b.dam, b.cam"
I have a string like www.host.com and I need to remove beginning from it (in this case www.) to make it just host.com. There is array of these beginnings (like: m., wap. and so on). How to do it in effective and fast way?
Currently I am using this code, but I think there should be a better/faster/cleaner way:
<?php
function _without_start( $val, $start )
{
if( _starts( $val, $start ) )
{
$len = mb_strlen( $start );
$val = mb_substr( $val, $len );
}
return $val;
}
function _starts( $str, $needle )
{
return ( mb_substr( $str, 0, mb_strlen($needle) ) === $needle );
}
/********************************************/
$host = 'www.host.com';
$remove_from_beginning = array( 'www.', 'wap.', 'admin.' );
foreach( $remove_from_beginning as $start )
{
$host = _without_start( $host, $start );
}
var_dump( $host );
You dont need foreach for removing somethings from string, this one will be better,
$url = preg_replace("/^(www|wap)\./si","","www.wap.com");
echo $url;
With explode and in_array:
function _without_start($host, $prefixes) {
list($prefix, $remainder) = explode('.', $host, 2);
return in_array($prefix, $prefixes) ? $remainder : $host;
}
$prefixes = ['www', 'wap', 'admin'];
$host = 'www.host.com';
echo _without_start($host, $prefixes);
Since you added a Regex tag you can make a list using alteration in regex and check it against the string and replace with empty string.
Regex: ^(www|admin|wap)\.
Regex101 Demo
If you are up for a regex based solution (as one of the tag mentions regex), here you go
$remove_from_beginning = array( 'www.', 'wap.', 'admin.' );
$final = "";
foreach( $remove_from_beginning as $start )
{
$final = $final . "" . substr_replace($start, '', -1) . "" . "\.|";
}
$final = substr_replace($final, '', -1);
echo preg_replace("/" . "" . "(?:" . "" . $final . "" . ")" . "" . "(.*)" . "" . "/", "$1", "www.exaple.com");
Ideone Demo
I have a question and I thought you guys could be able to help me out with it.
I am making a custom blog and I found on the internet a very cool php file that provided these functions
function _make_url_clickable_cb($matches) {
$ret = '';
$url = $matches[2];
if ( empty($url) )
return $matches[0];
// removed trailing [.,;:] from URL
if ( in_array(substr($url, -1), array('.', ',', ';', ':')) === true ) {
$ret = substr($url, -1);
$url = substr($url, 0, strlen($url)-1);
}
return $matches[1] . "$url" . $ret;
}
I would like to have a function that would automatically detect when the link posted is an image (jpg, gif, png, etc) and automatically add the img tag.
I tried changing from this, but I am not really good with regexes
function _make_img_tag($matches) {
$ret = '';
$url = $matches[2];
if ( empty($url) )
return $matches[0];
if ( in_array(substr($url, -1), array('.', ',', ';', ':')) === true ) {
$ret = substr($url, -1);
$url = substr($url, 0, strlen($url)-1);
}
return $matches[1] . "<img src=\"$url\" width=\"800\" height=\"600\">$url" . $ret;
}
and then
$ret = preg_replace_callback('#^(gif|png|jpg|jpeg)#is', '_make_img_tag', $ret);
But it only shows as a link because of the other replace callbacks that have been added.
Can you guys please help me?
Thanks in advance,
edit: posting the full code
function _make_url_clickable_cb($matches) {
$ret = '';
$url = $matches[2];
if ( empty($url) )
return $matches[0];
// removed trailing [.,;:] from URL
if ( in_array(substr($url, -1), array('.', ',', ';', ':')) === true ) {
$ret = substr($url, -1);
$url = substr($url, 0, strlen($url)-1);
}
return $matches[1] . "$url" . $ret;
}
function _make_web_ftp_clickable_cb($matches) {
$ret = '';
$dest = $matches[2];
$dest = 'http://' . $dest;
if ( empty($dest) )
return $matches[0];
// removed trailing [,;:] from URL
if ( in_array(substr($dest, -1), array('.', ',', ';', ':')) === true ) {
$ret = substr($dest, -1);
$dest = substr($dest, 0, strlen($dest)-1);
}
return $matches[1] . "$dest" . $ret;
}
function _make_email_clickable_cb($matches) {
$email = $matches[2] . '#' . $matches[3];
return $matches[1] . "$email";
}
function _make_img_tag($matches) {
$ret = '';
$url = $matches[2];
if ( empty($url) )
return $matches[0];
if ( in_array(substr($url, -1), array('.', ',', ';', ':')) === true ) {
$ret = substr($url, -1);
$url = substr($url, 0, strlen($url)-1);
}
return $matches[1] . "<img src=\"$url\" width=\"800\" height=\"600\">$url" . $ret;
}
function make_clickable($ret) {
$ret = ' ' . $ret;
$ret = preg_replace_callback('#^(gif|png|jpg|jpeg)#is', '_make_img_tag', $ret);
$ret = preg_replace_callback('#([\s>])([\w]+?://[\w\\x80-\\xff\#$%&~/.\-;:=,?#\[\]+]*)#is', '_make_url_clickable_cb', $ret);
$ret = preg_replace_callback('#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?#\[\]+]*)#is', '_make_web_ftp_clickable_cb', $ret);
$ret = preg_replace_callback('#([\s>])([.0-9a-z_+-]+)#(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $ret);
$ret = preg_replace("#(<a( [^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i", "$1$3</a>", $ret);
$ret = trim($ret);
return $ret;
}
You do not need a new regular expression to find the images. These two lines already find them :
$ret = preg_replace_callback('#([\s>])([\w]+?://[\w\\x80-\\xff\#$%&~/.\-;:=,?#\[\]+]*)#is', '_make_url_clickable_cb', $ret);
$ret = preg_replace_callback('#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?#\[\]+]*)#is', '_make_web_ftp_clickable_cb', $ret);
What you need is distinguish a regular URL from an image in the functions that do the replacements. Replace
return $matches[1] . "$url" . $ret;
by
if (preg_match('#\.(gif|png|jpg|jpeg)$#is', $url))
return $matches[1] . "<img src=\"$url\" width=\"800\" height=\"600\">$url" . $ret;
else
return $matches[1] . "$url" . $ret;
I have a function below:
function make_clickable($ret) {
$ret = ' ' . $ret;
// in testing, using arrays here was found to be faster
$save = #ini_set('pcre.recursion_limit', 10000);
$retval = preg_replace_callback('#(?<!=[\'"])(?<=[*\')+.,;:!&$\s>])(\()?([\w]+?://(?:[\w\\x80-\\xff\#%~/?#\[\]-]{1,2000}|[\'*(+.,;:!=&$](?![\b\)]|(\))?([\s]|$))|(?(1)\)(?![\s<.,;:]|$)|\)))+)#is', '_make_url_clickable_cb', $ret);
if (null !== $retval )
$ret = $retval;
#ini_set('pcre.recursion_limit', $save);
$ret = preg_replace_callback('#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?#\[\]+]+)#is', '_make_web_ftp_clickable_cb', $ret);
$ret = preg_replace_callback('#([\s>])([.0-9a-z_+-]+)#(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $ret);
// this one is not in an array because we need it to run last, for cleanup of accidental links within links
$ret = preg_replace("#(<a( [^>]+?>|>))<a [^>]+?>([^>]+?)</a></a>#i", "$1$3</a>", $ret);
$ret = trim($ret);
return $ret;
}
And three callbacks which the function above calls to return the formatted string using preg_replace_callback.
function _make_url_clickable_cb($matches) {
$url = $matches[2];
$suffix = '';
/** Include parentheses in the URL only if paired **/
while ( substr_count( $url, '(' ) < substr_count( $url, ')' ) ) {
$suffix = strrchr( $url, ')' ) . $suffix;
$url = substr( $url, 0, strrpos( $url, ')' ) );
}
$url = esc_url($url);
if ( empty($url) )
return $matches[0];
$test = parse_url($url);
if ($test['host'] == 'www.flickr.com' || $test['host'] == 'www.youtube.com') {
return $matches[1] . "<a href=\"$url\" rel=\"nofollow\" class='oembed' target='_blank'>$url</a>" . $suffix;
}
else {
return $matches[1] . "<a href=\"$url\" rel=\"nofollow\" target='_blank'>$url</a>" . $suffix;
}
}
function _make_web_ftp_clickable_cb($matches) {
$ret = '';
$dest = $matches[2];
$dest = 'http://' . $dest;
$dest = esc_url($dest);
if ( empty($dest) )
return $matches[0];
// removed trailing [.,;:)] from URL
if ( in_array( substr($dest, -1), array('.', ',', ';', ':', ')') ) === true ) {
$ret = substr($dest, -1);
$dest = substr($dest, 0, strlen($dest)-1);
}
$test = parse_url($dest);
if ($test['host'] == 'www.flickr.com' || $test['host'] == 'www.youtube.com') {
return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\" class='oembed' target='_blank'>$dest</a>" . $suffix;
}
else {
return $matches[1] . "<a href=\"$dest\" rel=\"nofollow\" target='_blank'>$dest</a>" . $suffix;
}
}
function _make_email_clickable_cb($matches) {
$email = $matches[2] . '#' . $matches[3];
return $matches[1] . "$email";
}
This all works perfectly. However, when this is put inside a class with the main function (make_clickable) set as a public function and the three callbacks set to private. It does not work.
How would I go about calling suning the callbacks I have specificed for preg_replace_callback, within a class?
try this as the function name:
array($this, "_mke_web_ftp_clickable_cb")
Yo, i'm trying to do this script working, but it doesn't work. How do i do it twice, the preg_replace_callback with two different functions. Thanks!
function prepend_proxy($matches) {
$url = (substr($_GET['url'], 0, 7) == 'http://') ? $_GET['url'] : "http://{$_GET['url']}";
$prepend = $matches[2] ? $matches[2] : $url;
$prepend = 'proxy2.php?url='. $prepend .'/';
return $matches[1] . $prepend . $matches[3];
}
function imgprepend_proxy($matches2) {
$url = (substr($_GET['url'], 0, 7) == 'http://') ? $_GET['url'] : "http://{$_GET['url']}";
$prepend2 = $matches2[2] ? $matches2[2] : $url;
$prepend2 = $prepend2 .'/';
return $matches2[1] . $prepend2 . $matches2[3];
}
$new_content = preg_replace_callback(
'|(href=[\'"]?)(https?://)?([^\'"\s]+[\'"]?)|i',
'prepend_proxy',
'|(src=[\'"]?)(https?://)?([^\'"\s]+[\'"]?)|i',
'imgprepend_proxy',
$content
);
$new_content = preg_replace_callback(
'|(href=[\'"]?)(https?://)?([^\'"\s]+[\'"]?)|i',
'prepend_proxy',
preg_replace_callback(
'|(src=[\'"]?)(https?://)?([^\'"\s]+[\'"]?)|i',
'imgprepend_proxy',
$content
)
);