preg_replace everything but # sign - php

I've searched for an example of this, but can't seem to find it.
I'm looking to replace everything for a string but the #texthere
$Input = this is #cool isn't it?
$Output = #cool
I can remove the #cool using preg_replace("/#(\w+)/", "", $Input); but can't figure out how to do the opposite

You could match #\w+ and then replace the original string. Or, if you need to use preg_replace, you should be able to replace everything with the first capture group:
$output = preg_replace('/.*(#\w+).*/', '\1', $input);
Solution using preg_match (I assume this will perform better):
$matches = array();
preg_match('/#\w+/', $input, $matches);
$output = $matches[0];
Both patterns above do not address the issue how to handle inputs which match multiple times, such as this is #cool and #awesome, right?

Related

How to not perform preg_replace if subject starts with quote

I'm trying to convert plain links to HTML links using preg_replace. However it's replacing links that are already converted.
To combat this I'd like it to ignore the replacement if the link starts with a quote.
I think a positive lookahead may be needed but everything I've tried hasn't worked.
$string = 'test http://www.example.com';
$string = preg_replace("/((https?:\/\/[\w]+[^ \,\"\n\r\t<]*))/is", "$1", $string);
var_dump($string);
The above outputs:
http://www.example.com">test</a> http://www.example.com
When it should output:
test http://www.example.com
You might get along with lookarounds.
Lookarounds are zero-width assertions that make sure to match/not to match anything immediately around the string in question. They do not consume any characters.
That being said, a negative lookbehind might be what you need in your situation:
(?<![">])\bhttps?://\S+\b
In PHP this would be:
<?php
$string = 'I want to be transformed to a proper link: http://www.google.com ';
$string .= 'But please leave me alone ';
$string .= '(https://www.google.com).';
$regex = '~ # delimiter
(?<![">]) # a neg. lookbehind
https?://\S+ # http:// or https:// followed by not a whitespace
\b # a word boundary
~x'; # verbose to enable this explanation.
$string = preg_replace($regex, "<a href='$0'>$0</a>", $string);
echo $string;
?>
See a demo on ideone.com. However, maybe a parser is more appropriate.
Since you can use Arrays in preg_replace, this might be convenient to use depending on what you want to achieve:
<?php
$string = 'test http://www.example.com';
$rx = array("&(<a.+https?:\/\/[\w]+[^ \,\"\n\r\t<]*>)(.*)(<\/a\>)&si", "&(\s){1,}(https?:\/\/[\w]+[^ \,\"\n\r\t<]*)&");
$rp = array("$1$2$3", "$2");
$string = preg_replace($rx,$rp, $string);
var_dump($string);
// DUMPS:
// 'testhttp://www.example.com'
The Idea
You can split your string at the already existing anchors, and only parse the pieces in between.
The Code
$input = 'test http://www.example.com';
// Split the string at existing anchors
// PREG_SPLIT_DELIM_CAPTURE flag includes the delimiters in the results set
$parts = preg_split('/(<a.*?>.*?<\/a>)/is', $input, PREG_SPLIT_DELIM_CAPTURE);
// Use array_map to parse each piece, and then join all pieces together
$output = join(array_map(function ($key, $part) {
// Because we return the delimiter in the results set,
// every $part with an uneven key is an anchor.
return $key % 2
? preg_replace("/((https?:\/\/[\w]+[^ \,\"\n\r\t<]*))/is", "$1", $part)
: $part;
}, array_keys($parts), $parts);

Regex replace recursive with one pattern

$array[key][key]...[key]
replace to
$array['key']['key']...['key']
I managed only to add quotes to the first keyword of the array.
\$([a-zA-Z0-9]+)\[([a-zA-Z_-]+[0-9]*)\] replace to \$\1\[\'\2\3\'\]
You may use a regex that does not perform a recursive, but consecutive matching:
$re = '/(\$\w+|(?!^)\G)\[([^]]*)\]/';
$str = "\$array[key][key][key]";
$subst = "$1['$2']";
$result = preg_replace($re, $subst, $str);
echo $result;
See IDEONE demo
The regex (\$\w+|(?!^)\G)\[([^]]*)\] matches all square parenthetical substrings (capturing their contents into Group 2) (with \[([^]]*)\]) that either are right after a '$'+alphanumerics substring (due to the \$\w+ part) or that follow one another consecutively (thanks to (?!^)\G).
Shouldn't need anything fancy, just get the stuff you need then
replace in a callback.
Untested:
$new_input = preg_replace_callback('/(?i)\$[a-z]+\K(?:\[[^\[\]]*\])+/',
function( $matches ){
return preg_replace( '/(\[)|(\])/', "$1'$2", $matches[0]);
},
$input );

Why is my regex rejecting apostrophes?

I'm making a regex which should match everything like that : [[First example]] or [[I'm an example]].
Unfortunately, it doesn't match [[I'm an example]] because of the apostrophe.
Here it is :
preg_replace_callback('/\[\[([^?"`*%#\\\\:<>]+)\]\]/iU', ...)
Simple apostrophes (') are allowed so I really do not understand why it doesn't work.
Any ideas ?
EDIT : Here is what's happening before I'm using this regex
// This match something [[[like this]]]
$contents = preg_replace_callback('/\[\[\[(.+)\]\]\]/isU',function($matches) {
return '<blockquote>'.$matches[1].'</blockquote>';
}, $contents);
// This match something [[like that]] but doesn't work with apostrophe/quote when
// the first preg_replace_callback has done his job
$contents = preg_replace_callback('/\[\[([^?"`*%#\\\\:<>]+)\]\]/iU', ..., $contents);
try this:
$string = '[[First example]]';
$pattern = '/\[\[(.*?)\]\]/';
preg_match ( $pattern, $string, $matchs );
var_dump ( $matchs );
You can use this regex:
\[\[.*?]]
Working demo
Php code
$re = '/\[\[.*?]]/';
$str = "not match this but [[Match this example]] and not this";
preg_match_all($re, $str, $matches);
Btw, if you want to capture the content within brackets you have to use capturing groups:
\[\[(.*?)]]

Issue with regular expression for identifying encrypted ids from string

I want to convert certain patterns into links and it works fine as far as normal user ids are considered.But now i want to do the same for encrypted ids as well.
Below is my code:(works)
$text = "hi how are you guys???... ##[Sam Thomas:10181] ##[Jack Daniel:11074] ##[Paul Walker:11043] ";
$pattern = "/##\[([^:]*):(\d*)\]/";
$matches = array();
preg_match_all($pattern, $text, $matches);
$output = preg_replace($pattern, "$1", $text);
Now i need to do link the text like:
"hi how are you guys???... ##[Sam Thomas:ZGNjAmD9ac3K] ##[Jack Daniel:ZGNjAmD9ac3K] ##[Paul Walker:ZGNjAmD9ac3K] ";
But this encrypted is not identified by above regular expression...
##\[([^:]*):(.*?)\]
^^
Try this.See demo.Just change \d* to .*? to accept anything or \w* to accept only numbers and letters.or [^\]]* or [0-9a-zA-Z] as well.
https://regex101.com/r/vD5iH9/52
Change your regex to accept numbers and letters as well.
Something like this -
##\[([^:]*):([0-9a-zA-Z]*)\]
^^^^^^^^^^^ Replaced \d
Demo

Can't get PHP Regex working

I'm trying to use PHP regular expressions. I've tried this code:
$regex = "c:(.+),";
$input = "otherStuff094322f98c:THIS,OtherStuffHeree129j12dls";
$match = Array();
preg_match_all($regex, $input, $match);
It should return a sub-string THIS ("c" and ":" followed by any character combination followed by ",") from $input. But it returns a empty array. What am I doing wrong?
I think you need the slashes to make regex working.
and using .+ will match everything behind the comma too, which is you don't want. Use .+? or [^,]+
$regex = "/c:(.+?),/";
or
$regex = "/c:([^,]+),/";

Categories