PHP regex remove all digits except character codes - php

As per this thread it's pretty easy to remove all digits from a string in PHP.
For example:
$no_digits = preg_replace('/\d/', '', 'This string contains digits! 1234');
But, I don't want digits removed that are part of HTML charactr codes such as:
)
©
How can I get Regex to ignore numbers that are part of a HTML character code? i.e. numbers that are sandwiched between &# and ; characters?

You can use (*SKIP)(*F) verb:
echo preg_replace('/&#\d+;(*SKIP)(*F)|\d+/', '',
'This string contains digits! 1234 ) © 5678');
//=> This string contains digits! ) ©
&#\d+;(*SKIP)(*F) will skip the match id regex matches &#\d+; pattern.
Alternatively you can use lookarounds:
echo preg_replace('/(?<!&#)\d+|\d+(?!;)/', '',
'This string contains digits! 1234 ) © 5678');
Which means match 1 or digits that are either not preceded by &# OR not followed by ; thus making it skip &#\d+; pattern.

You can use
var output = Regex.Replace(input, #"[\d-]", string.Empty);
***The \d identifier simply matches any digit character.

As an option, you could convert your code to UTF-8 encoding (if it’s not already UTF-8), then convert HTML entities to corresponding characters with html_entity_decode(), then remove numbers with a regexp, then, if needed, convert special characters to corresponding entities again with htmlentities() (in UTF-8, it’s actually enough to escape just a minimal subset of special characters via htmlspecialchars()), then convert code back to your original encoding (if the original string was not in UTF-8).

You can use look behind and look ahead.
$no_digits = preg_replace('/(?<!&#)\d+(?=[^;\d])/', '', 'This string contains ) digits! 1234');
So basically, (?<!&#) tells RegEx to look behind \d+ to make sure that there is no &# and (?=[^;\d]) tells RegEx to look ahead of \d+ to make sure that it is not a semicolon or a number.
I like this solution a bit better as it can be used on most RegEx like in Java and JavaScript.
Hope this helps.
Edit: miss one character <.

Related

Regexp grab all text following last match

I am trying to grab the text after the last number in the string and grab the whole string if it doesn't contain numbers.
The best regex I could come up with is:
([^\d\s]*)$
However I found that \s and \d aren't supported in mysql regexp rather [[:space:]] and not sure what \d is equivalent too.
This is what I'm trying to accomplish:
'1/2 Oz' returns 'Oz'
'2 3/4 Oz' returns 'Oz'
'As needed' returns 'As needed'
This is the regex you will need:
/^.*?(\d+(?=\D*$)\s*)/
And just replace matched text with empty string ""
PHP code:
$s = preg_replace('/^.*?(\d+(?=\D*$)\s*)/', '', 'Foo Oz');
//=> Foo Oz
$s = preg_replace('/^.*?(\d+(?=\D*$)\s*)/', '', '1/2 Oz');
//=> Oz
Live Demo: http://ideone.com/u887D7
First of all, you could simply avoid the class, and use a range instead:
[^0-9[:space:]]*$
But there is one for digits as well (which may actually include non-ASCII digits). The documentation has a list of these. They are called POSIX bracket expressions by the way.
[^[:digit:][:space:]]*$
However, the general problem with this approach is that it doesn't allow for spaces later on in the string (like the one between As and needed. To get those, but still avoid capturing trailing spaces after digits, make sure, the first character is neither space nor digit, then match the rest of the string as non-digits. In addition, make the whole thing optional, to ensure that it still works with strings ending in a digit.
([^[:digit:][:space:]][^:digit:]*)?$

remove whatever i want from string

I got a few keywords, symbols, letters etc I want to remove from my php string. I'm trying to add it but it doesn't work too well.
$string = preg_replace("/(?![=$'%-mp4mp3])\p{P}/u","", $check['title']);
pretty much I want to to remove word mp3, mp4, ./, apples from the string.
Please help guide me, thanks in advance!
First: [] in regular expression introduces a character class. A hyphen is used to represent a character range between two symbols. So the reason your regular expression would make too many erasures (as I suppose) is because [=$'%-mp4mp3] means =, $, ', everything from % to m (72 characters actually!), p, 3, 4.
Second: your regular expression doesn't grab "bad" characters/keywords. Actually, you erase punctuation after bad characters/keywords, as negative lookahead is meta sequence (it is not included in match).
Change your regex to:
"/[=$'%-]|mp3|mp4/u"
You don't need regex for that.
$string = "Your original string here";
$keywords = array('mp3', 'mp4');
echo str_replace($keywords, '', $string);

How to replace only the last match of a string with preg_replace?

I have to replace the last match of a string (for example the word foo) in HTML document. The problem is that the structure of the HTML document is always random.
I'm trying to accomplish that with preg_replace, but so far I know how to replace only the first match, but not the last one.
Thanks.
Use negative look after (?!...)
$str = 'text abcd text text efgh';
echo preg_replace('~text(?!.*text)~', 'bar', $str),"\n";
output:
text abcd text bar efgh
A common approach to match all text to the last occurrence of the subsequent pattern(s) is using a greedy dot, .*. So, you may match and capture the text before the last text and replace with a backreference + the new value:
$str = 'text abcd text text efgh';
echo preg_replace('~(.*)text~su', '${1}bar', $str);
// => text abcd text bar efgh
If text is some value inside a variable that must be treated as plain text, use preg_quote to ensure all special chars are escaped correctly:
preg_replace('~(.*)' . preg_quote($text, '~') . '~su', '${1}bar', $str)
See the online PHP demo and a regex demo.
Here, (.*) matches and captures into Group 1 any zero or more chars (note that the s modifier makes the dot match line break chars, too), as many as possible, up to the rightmost (last) occurrence of text. If text is a Unicode substring, the u modifier comes handy in PHP (it enables (*UTF) PCRE verb allowing parsing the incoming string as a sequence of Unicode code points rather than bytes and the (*UCP) verb that makes all shorthand character classes Unicode aware - if any).
The ${1} is a replacement backreference, a placeholder holding the value captured into Group 1 that lets restore that substring inside the resulting string. You can use $1, but a problem might arise if the $text starts with a digit.
An example
<?php
$str = 'Some random text';
$str_Pattern = '/[^ ]*$/';
preg_match($str_Pattern, $str, $results);
print $results[0];
?>
Of course the accepted solution given here is correct. Nevertheless you might also want to have a look at this post. I'm using this where no pattern is needed and the string does not contain characters that could not be captured by the functions used (i.e. multibyte ones). I also put an additional parameter for dis/regarding case.
The first line then is:
$pos = $case === true ? strripos($subject, $search) : strrpos($subject, $search);
I have to admit that I did not test the performance. However, I guess that preg_replace() is slower, specially on large strings.

How can I create my own regex for "parse" HTML links?

The strings looks like hyperlinks, such as http://somethings. This is what I need :
I need to check them only if they doesnt start with the character "; I mean, only that characters : if before there aren't characters it must check;
That somethings string means that every kind of characters can be used (of course, is a link) except a whitespace (The end marker link); I know, it's permitted by RFC, but is the only way I know to escape;
these string are previously filtered by using htmlentities($str, ENT_QUOTES, "UTF-8"), that's why every kind of characters can be used. Is it secure? Or I risk problems with xss or html broked?
the occurences of this replacement can me multiple, not only 1, and must be case insenstive;
This is my actual regex :
preg_replace('#\b[^"](((http|https|ftp)://).+)#', '<a class="lforum" href="$1">$1</a>', $str);
But it check only those string that START with ", and I want the opposite. Any helps answering to this question would be good, Thanks!
For both of your cases you'll want lookbehind assertions.
\b(?<!")(\w)\b - negative lookbehind to match only if not preceded by "
(?<=ThisShouldBePresent://)(.*) - positive lookbehind to match only if preceded by the your string.
Something like this: preg_match('/\b[^"]/',$input_string);
This looks for a word-break (\b), followed by any character other than a double quote ([^"]).
Something like this: preg_match('~(((ThisShouldBePresent)://).+)~');
I've assumed the brackets you specified in the question (and the plus sign) were intended as part of the regex rather than characters to search for.
I've also taken #ThiefMaster's advice and changed the delimiter to ~ to avoid having to escape the //.

Remove control characters from PHP string

How can I remove control characters like STX from a PHP string? I played around with
preg_replace("/[^a-zA-Z0-9 .\-_;!:?äÄöÖüÜß<>='\"]/","",$pString)
but found that it removed way to much. Is there a way to remove only
control chars?
If you mean by control characters the first 32 ascii characters and \x7F (that includes the carriage return, etc!), then this will work:
preg_replace('/[\x00-\x1F\x7F]/', '', $input);
(Note the single quotes: with double quotes the use of \x00 causes a parse error, somehow.)
The line feed and carriage return (often written \r and \n) may be saved from removal like so:
preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/', '', $input);
I must say that I think Bobby's answer is better, in the sense that [:cntrl:] better conveys what the code does than [\x00-\x1F\x7F].
WARNING: ereg_replace is deprecated in PHP >= 5.3.0 and removed in PHP >= 7.0.0!, please use preg_replace instead of ereg_replace:
preg_replace('/[[:cntrl:]]/', '', $input);
For Unicode input, this will remove all control characters, unassigned, private use, formatting and surrogate code points (that are not also space characters, such as tab, new line) from your input text. I use this to remove all non-printable characters from my input.
<?php
$clean = preg_replace('/[^\PC\s]/u', '', $input);
for more info on \p{C} see http://www.regular-expressions.info/unicode.html#category
PHP does support POSIX-Classes so you can use [:cntrl:] instead of some fancy character-magic-stuff:
ereg_replace("[:cntrl:]", "", $pString);
Edit:
A extra pair of square brackets might be needed in 5.3.
ereg_replace("[[:cntrl:]]", "", $pString);
TLDR Answer
Use this Regex...
/[^\PCc^\PCn^\PCs]/u
Like this...
$text = preg_replace('/[^\PCc^\PCn^\PCs]/u', '', $text);
TLDR Explanation
^\PCc : Do not match control characters.
^\PCn : Do not match unassigned characters.
^\PCs : Do not match UTF-8-invalid characters.
Working Demo
Simple demo to demonstrate: IDEOne Demo
$text = "\u{0019}hello";
print($text . "\n\n");
$text = preg_replace('/[^\PCc^\PCn^\PCs]/u', '', $text);
print($text);
Output:
(-Broken-Character)hello
hello
Alternatives
^\PC : Match only visible characters. Do not match any invisible characters.
^\PCc : Match only non-control characters. Do not match any control characters.
^\PCc^\PCn : Match only non-control characters that have been assigned. Do not match any control or unassigned characters.
^\PCc^\PCn^\PCs : Match only non-control characters that have been assigned and are UTF-8 valid. Do not match any control, unassigned, or UTF-8-invalid characters.
^\PCc^\PCn^\PCs^\PCf : Match only non-control, non-formatting characters that have been assigned and are UTF-8 valid. Do not match any control, unassigned, formatting, or UTF-8-invalid characters.
Source and Explanation
Take a look at the Unicode Character Properties available that can be used to test within a regex. You should be able to use these regexes in Microsoft .NET, JavaScript, Python, Java, PHP, Ruby, Perl, Golang, and even Adobe. Knowing Unicode character classes is very transferable knowledge, so I recommend using it!
This regex will match anything visible, given in both its short-hand and long-hand form...
\PL\PM\PN\PP\PS\PZ
\PLetter\PMark\PNumber\PPunctuation\PSymbol\PSeparator
Normally, \p indicates that it's something we want to match and we use \P (capitalized) to indicate something that does not match. But PHP doesn't have this functionality, so we need to use ^ in the regex to do a manual negation.
A simpler regex then would be ^\PC, but this might be too restrictive in deleting invisible formatting. You may want to look closely and see what's best, but one of the alternatives should fit your needs.
All Matchable Unicode Character Sets
If you want to know any other character sets available, check out regular-expressions.info...
\PL or \PLetter: any kind of letter from any language.
\PLl or \PLowercase_Letter: a lowercase letter that has an uppercase variant.
\PLu or \PUppercase_Letter: an uppercase letter that has a lowercase variant.
\PLt or \PTitlecase_Letter: a letter that appears at the start of a word when only the first letter of the word is capitalized.
\PL& or \PCased_Letter: a letter that exists in lowercase and uppercase variants (combination of Ll, Lu and Lt).
\PLm or \PModifier_Letter: a special character that is used like a letter.
\PLo or \POther_Letter: a letter or ideograph that does not have lowercase and uppercase
\PM or \PMark: a character intended to be combined with another character (e.g. accents, umlauts, enclosing boxes, etc.).
\PMn or \PNon_Spacing_Mark: a character intended to be combined with another
character without taking up extra space (e.g. accents, umlauts, etc.).
\PMc or \PSpacing_Combining_Mark: a character intended to be combined with another character that takes up extra space (vowel signs in many Eastern languages).
\PMe or \PEnclosing_Mark: a character that encloses the character it is combined with (circle, square, keycap, etc.).
\PZ or \PSeparator: any kind of whitespace or invisible separator.
\PZs or \PSpace_Separator: a whitespace character that is invisible, but does take up space.
\PZl or \PLine_Separator: line separator character U+2028.
\PZp or \PParagraph_Separator: paragraph separator character U+2029.
\PS or \PSymbol: math symbols, currency signs, dingbats, box-drawing characters, etc.
\PSm or \PMath_Symbol: any mathematical symbol.
\PSc or \PCurrency_Symbol: any currency sign.
\PSk or \PModifier_Symbol: a combining character (mark) as a full character on its own.
\PSo or \POther_Symbol: various symbols that are not math symbols, currency signs, or combining characters.
\PN or \PNumber: any kind of numeric character in any script.
\PNd or \PDecimal_Digit_Number: a digit zero through nine in any script except ideographic scripts.
\PNl or \PLetter_Number: a number that looks like a letter, such as a Roman numeral.
\PNo or \POther_Number: a superscript or subscript digit, or a number that is not a digit 0–9 (excluding numbers from ideographic scripts).
\PP or \PPunctuation: any kind of punctuation character.
\PPd or \PDash_Punctuation: any kind of hyphen or dash.
\PPs or \POpen_Punctuation: any kind of opening bracket.
\PPe or \PClose_Punctuation: any kind of closing bracket.
\PPi or \PInitial_Punctuation: any kind of opening quote.
\PPf or \PFinal_Punctuation: any kind of closing quote.
\PPc or \PConnector_Punctuation: a punctuation character such as an underscore that connects words.
\PPo or \POther_Punctuation: any kind of punctuation character that is not a dash, bracket, quote or connector.
\PC or \POther: invisible control characters and unused code points.
\PCc or \PControl: an ASCII or Latin-1 control character: 0x00–0x1F and 0x7F–0x9F.
\PCf or \PFormat: invisible formatting indicator.
\PCo or \PPrivate_Use: any code point reserved for private use.
\PCs or \PSurrogate: one half of a surrogate pair in UTF-16 encoding.
\PCn or \PUnassigned: any code point to which no character has been assigned.
To keep the control characters but make them compatible for JSON, I had to to
$str = preg_replace(
array(
'/\x00/', '/\x01/', '/\x02/', '/\x03/', '/\x04/',
'/\x05/', '/\x06/', '/\x07/', '/\x08/', '/\x09/', '/\x0A/',
'/\x0B/','/\x0C/','/\x0D/', '/\x0E/', '/\x0F/', '/\x10/', '/\x11/',
'/\x12/','/\x13/','/\x14/','/\x15/', '/\x16/', '/\x17/', '/\x18/',
'/\x19/','/\x1A/','/\x1B/','/\x1C/','/\x1D/', '/\x1E/', '/\x1F/'
),
array(
"\u0000", "\u0001", "\u0002", "\u0003", "\u0004",
"\u0005", "\u0006", "\u0007", "\u0008", "\u0009", "\u000A",
"\u000B", "\u000C", "\u000D", "\u000E", "\u000F", "\u0010", "\u0011",
"\u0012", "\u0013", "\u0014", "\u0015", "\u0016", "\u0017", "\u0018",
"\u0019", "\u001A", "\u001B", "\u001C", "\u001D", "\u001E", "\u001F"
),
$str
);
(The JSON rules state: “All Unicode characters may be placed within the quotation marks except for the characters that must be escaped: quotation mark, reverse solidus, and the control characters (U+0000 through U+001F).”)
regex free method
If you are only zapping the control characters I'm familiar with (those under 32 and 127), try this out:
for($control = 0; $control < 32; $control++) {
$pString = str_replace(chr($control), "", $pString;
}
$pString = str_replace(chr(127), "", $pString;
The loop gets rid of all but DEL, which we just add to the end.
I'm thinking this will be a lot less stressful on you and the script then dealing with regex and the regex library.
Updated regex free method
Just for kicks, I came up with another way to do it. This one does it using an array of control characters:
$ctrls = range(chr(0), chr(31));
$ctrls[] = chr(127);
$clean_string = str_replace($ctrls, "", $string);

Categories