Regular expression matching in php - php

I have this regexp:
/(.*)(([0-9]([^a-zA-Z])*){7,}[0-9])(.*)/.
Given the following values
0654535263
065453-.-5263
065asd4535263
Expected Results
06****
06****
06****
Actual Results
0654535263
06****
065asd4535263
It does not match the last row because of the letters (I want to match from 0-3 letters) and it matches only last occurence (in the second row in example, it skips first row).
First of all thank u all oyur answers are very helpfull and i owe u a bih time. I cant create array of numbers and mask them like that because i can have string like this:
I am John, I live bla bla my phone is: 0, 6, 5, 4, 5, 3, 5, 2, 6 - 3 -- 065asd4535263.
To simplify i want to hide entered mobile number.
I had two problems:
change regxp mentioned above, to hide digits separated by no more than 3 chars.
preg_replace was replacing only one occurence.
At the end i just need regexp to replace any array of digits, at least 6 digits long, separated by any number of special chars (12--654-5, 453/--222, 23....5645 etc) OR no more than 3 chars (ltters) (06asd453, 123as562).
Thank you again, all answers are vry helpfull, but i am gulty because i didnt formulated my question right.
p.s. i cant give u reputation because i must have at least 15, as soon as i get that much, i will 'vote up', all answers deserve it.

Hmm why so complicated when you only want to mascarade your string.
$input = '0654535263';
$input = substr($input, 0, 2);
$output = $input . '********';
Its a bit easier when you only want the first 2 characters of your string. Perhaps your solution had another sin. But this is a bit easier.

You can just use substr_replace
echo substr_replace($v, "****", 2);
Example
$list = array("0654535263","065453-.-5263","065asd4535263");
echo "<pre>";
foreach ( $list as $v ) {
echo substr_replace($v, "****", 2), PHP_EOL;
}
Output
06****
06****
06****

I'm guessing that the reason you want to use regular expressions is so that you don't mask every string that you get. This regex checks that there is at least 2 digits in the beginning of the string, then 0 to 3 alphabet characters, and then all the rest of the characters of the string need to be non-alphabet characters. If it matches, it masks the string, otherwise it says the string does not match.
$string = '0654535263';
if(preg_match('~^(\d{2})\d*?[a-zA-Z]{0,3}[^a-zA-Z]*$~', $string))
$answer = preg_replace('~^(\d{2})\d*?[a-zA-Z]{0,3}[^a-zA-Z]*$~', '$1****', $string);
else
$answer = $string . ' does not match';
print_r($answer); // 06****

Related

Return xx characters before a certain string

So I have this string:
Best location using 168 cars + cleaning
The '168' is the part i'd like to extract from this string.
I have approximately 80 occurences of this string, all alternating from 'xx' cars to 'xxx' cars (so, 2 or 3 numbers). However, in each string, 'cars' comes after the number i'd like to return.
What would be the best way using PHP to achieve this?
The best way is to do a simple preg_match on the text.
See the tutorial: http://php.net/manual/en/function.preg-match.php
<?php
$string = 'Best location using 168 cars + cleaning';
$pattern = '/(\d{2,3}+) cars/';
preg_match($pattern, $string, $match);
echo $match[1];
This regex returns all the numbers with length of 2 to 3 before the word cars.
you can change the length as you want and \d means all the numbers.
Easiest way is probably via preg_match(). Look for a space, one or more digits, a space, then the word cars. Use parens to capture the digits. That gives you pattern like this:
' (\d+) cars'
Then just pass that to preg_match() with a third argument to capture the parenthesized substring:
if (preg_match('/ (\d+) cars/', $str, $match)) {
echo "your num is: " . $match[1] . "\n";
}
Note this will also capture 1 cars and 1234 cars. If that's a problem, and you want to ensure that you only get the values with two or three digits, you can tweak the pattern to explicitly require that:
' (\d{2,3}) cars'
I would explode the string on a space and then loop through the array looking for the string "cars" and then get the key value for this. From here you know that the number will be before the "cars" occurrence so minus 1 from this key value and look in the array.
$original_string = "Best location using 168 cars + cleaning";
$string = explode(" ", $original_string);
foreach ($string as $key => $part) {
if($part == "cars") {
$number = $string[$key-1];
}
}
Explanation:
$original_string is whatever your whole string where the number is unknown.
$string is an array of the $original_string, each word will be in it's own part of the array
we loop through this array looking for the string "cars" and also get its key value.
If we find it successfully we then go to the key value minus one to find the number. We do this because we know the number appears before the "cars" string.

Regular expression currency format with dots and comma

My goal is getting something like that: 150.000,54 or 48.876,05 which means my commas are decimal starters.
Here's my code so far :
<?php
//cut numbers after comma if there are any, after 2 digits
$matchPattern = '/[0-9]+(?:\,[0-9]{2}){0,2}/';
//remove everything except numbers, commas and dots
$repl1 = preg_replace("/[^a-zA-Z0-9,.]/", "", $input);
//let there be a 0 before comma to have values like 0,75
$repl2 = preg_replace("/^[0]{1}$/", "",$repl1);
//now i need you here to help me for the expression putting dots after each 3 numbers, until the comma:
$repl3 = preg_replace("/regexphere$/", ".", $repl2);
preg_match($matchPattern, $repl3, $matches);
echo($matches[0]);
?>
I know preg_replacing 3 times is stupid but I am not good at writing regular expressions. If you have a better idea, don't just share it but also explain. I know a little of the types : http://regexone.com/lesson/0
Thank you in advance.
--------UPDATE--------
So I need to handle 0000,45 like inputs to 0,45 and like 010101,84 inputs to 1,84
When this is done, I'm done.
$input = Input::get('userinput');
$repl1 = preg_replace("/[^0-9,.]/", "", $input);
$repl2 = preg_replace("/^0/", "",$repl1);
$repl3 = str_replace(".","",$repl2);
preg_match('/[0-9]+(?:\,[0-9]{2}){0,2}/', $repl3, $matches);
$repl4 = preg_replace('/(\d)(?=(\d{3})+(?!\d))/', '$1.', $matches[0]);
return repl4;
----UPDATE----
Here's what i get so far : https://ideone.com/5qmslB
I just need to remove the zeroes before the comma, before the numbers.
I am not sure this is the best way, but I hope it is helpful.
Here is the updated code that I used with a fake $input:
<?php
$input = "textmdwrhfejhg../,2222233333,34erw.re.ty";
//cut numbers after comma if there are any, after 2 digits
$matchPattern = '/[0-9]+(?:\,[0-9]{2}){0,2}/';
//remove everything except numbers, commas and dots
$repl1 = trim(preg_replace("/[^0-9,.]/", "", $input), ".,");
echo "$repl1" . "\n";
//let there be a 0 before comma to have values like 0,75, remove the 0
$repl2 = preg_replace("/^0/", "",$repl1);
echo "$repl2" . "\n";
//The expression putting dots after each 3 numbers, until the comma:
$repl3 = preg_replace('/(\d)(?=(?:\d{3})+(?!\d))/', '$1.', $repl2);
echo "$repl3" . "\n";
The expression putting dots after each 3 numbers is
(\d)(?=(?:\d{3})+(?!\d))
Here, you can see how it works. In plain human,
(\d) - A capturing group that we'll use in the replacement pattern, matching a single digit that....
(?=(?:\d{3})+(?!\d)) - is followed by groups of 3 digits. External (?=...) is a look-ahead construction that checks but does not consume characters, (?:\d{3})+ is a non-capturing group (no need to keep the matched text in memory) that matches 3 digits exactly (due to the limiting quantifier {3}) 1 or more times (due to the + quantifier), and (?!\d) is a negative look-ahead checking that the next character after the last matched 3-digit group is not a digit.
This does not work in case we have more than 3 digits after a decimal separator. With regex, I can only think of a way to support 4 digits after decimal with (?<!,)(\d)(?=(?:\d{3})+(?!\d)). Not sure if there is a generic way without variable-width look-behind in PHP (as here, we also need a variable-width look-ahead, too). Thus, you might consider splitting the $repl2 value by comma, and only pass the first part to the regex. Then, combine. Something like this:
$spl = split(',', $repl2); // $repl2 is 1234,123456
$repl3 = preg_replace('/(\d)(?=(?:\d{3})+(?!\d))/', '$1.', $spl[0]);
$repl3 .= "," . $spl[1]; // "1.234" + "," + "123456"
echo "$repl3" . "\n"; // 1.234,123456
Update:
The final code I have come up with:
$input = "textmdwrhfejhg../0005456,2222233333,34erw.re.ty";
//Here's mine :
$repl1 = trim(preg_replace("/[^0-9,.]/", "", $input), '.,');
//following line just removes one zero, i want it to remove all chars like
//Input : 000549,569 Output : 549,569
echo "$repl1\n";
$repl2 = preg_replace("/^0+(?!,)/", "",$repl1);
$repl3 = str_replace(".","",$repl2);
preg_match('/[0-9]+(?:\,[0-9]{2}){0,2}/', $repl3, $matches);
$repl4 = preg_replace('/(\d)(?=(\d{3})+(?!\d))/', '$1.', $matches[0]);
echo $repl4;

Remove characters from both left and right of a string in PHP

This is an example of a string: abcde123#ijklmn0pq
In that string I need to print out only the numbers (the 123 sequence), and remove the letters (from both left and right) and the hashtag (#) to be removed as well.
The hashtag (#) is always included in the string.
The hashtag (#) is always positioned to the right of the characters that need to be printed;
The hashtag (#) is always positioned to the left of the characters that need to be removed;
Therefore, the hashtag (#) can be used as a guide to remove the letters from the Right
The number of characters in the beginning is always equal to 5 (constant) (to be removed);
The number of characters in the middle is always different (variable) (to be printed);
The number of characters in the right is always different (variable) (to be removed);
Here's another string example, similar to the first one: !!##$IMPORTANT#=-=whatever
The characters that need to be printed are the word "IMPORTANT"
As with the first example, what's on the left side of the hashtag (#) needs to be printed, but it's important to print only the "IMPORTANT" word, without the special characters "!!##$".
$myString = '!!##$IMPORTANT#=-=whatever';
$result = substr($myString, 5, -1);
$pos = strpos($result, '#');
$result = substr($result, 0, $pos);
echo $result;
You can use regexes with preg_replace();
Assuming that the string you need to process is stored in $string:
preg_replace('^.{5}(.*)#.*$', '$1', $string);
https://www.regex101.com/r/hA8lY7/1
First pattern explanation:
^.{5}: matches any 5 character after the start of $string
(.*): matches any N character after (1) before the first occurence of # (first capturing-group)
#.*$: matches # and any N character after (2) before the end of $string
Second pattern explanation:
$1: replaces $string with the first capturing-group matched in the first pattern
Ill give a stab at this. seems pretty simple.
function choppy($choppy) {
$nstr = substr($choppy, 5,strlen($choppy)); //chop first 5
$pos = strpos($nstr, "#"); //Find the position of the hash tag
return substr($nstr, 0, $pos); //we only need the stuff before it...
}
echo choppy('!!##$IMPORTANT#=-=whatever');
echo "\n";
echo choppy('abcde123#ijklmn0pq');
Result
C:\Users\developer\Desktop>php test.php
IMPORTANT
123
The other answers are good but if you need a one-liner for your homework:
$str = '!!##$IMPORTANT#=-=whatever';
echo substr($str, 5, strpos($str, '#')-5); //IMPORTANT

Extract last section of string

I have a string like this:
[numbers]firstword[numbers]mytargetstring
I would like to know how is it possible to extract "targetstring" taking account the following :
a.) Numbers are numerical digits for example, my complete string with numbers:
12firstword21mytargetstring
b.) Numbers can be any digits, for example above are two digits each, but it can be any number of digits like this:
123firstword21567mytargetstring
Regardless of the number of digits, I am only interested in extracting "mytargetstring".
By the way "firstword" is fixed and will not change with any combination.
I am not very good in Regex so I appreciate someone with strong background can suggest how to do this using PHP. Thank you so much.
This will do it (or should do)
$input = '12firstword21mytargetstring';
preg_match('/\d+\w+\d+(\w+)$/', $input, $matches);
echo $matches[1]; // mytargetstring
It breaks down as
\d+\w+\d+(\w+)$
\d+ - One or more numbers
\w+ - followed by 1 or more word characters
\d+ - followed by 1 or more numbers
(\w+)$ - followed by 1 or more word characters that end the string. The brackets mark this as a group you want to extract
preg_match("/[0-9]+[a-z]+[0-9]+([a-z]+)/i", $your_string, $matches);
print_r($matches);
You can do it with preg_match and pattern syntax.
$string ='2firstword21mytargetstring';
if (preg_match ('/\d(\D*)$/', $string, $match)){
// ^ -- end of string
// ^ -- 0 or more
// ^^ -- any non digit character
// ^^ -- any digit character
var_dump($match[1]);}
Try it like,
print_r(preg_split('/\d+/i', "12firstword21mytargetstring"));
echo '<br/>';
echo 'Final string is: '.end(preg_split('/\d+/i', "12firstword21mytargetstring"));
Tested on http://writecodeonline.com/php/
You don't need regex for that:
for ($i=strlen($string)-1; $i; $i--) {
if (is_numeric($string[$i])) break;
}
$extracted_string = substr($string, $i+1);
Above it's probably the faster implementation you can get, certainly faster than using regex, which you don't need for this simple case.
See the working demo
your simple solution is here :-
$keywords = preg_split("/[\d,]+/", "hypertext123language2434programming");
echo($keywords[2]);

Split alphanumeric string between leading digits and trailing letters

I have a string like:
$Order_num = "0982asdlkj";
How can I split that into the 2 variables, with the number as one element and then another variable with the letter element?
The number element can be any length from 1 to 4 say and the letter element fills the rest to make every order_num 10 characters long in total.
I have found the php explode function...but don't know how to make it in my case because the number of numbers is between 1 and 4 and the letters are random after that, so no way to split at a particular letter.
You can use preg_split using lookahead and lookbehind:
print_r(preg_split('#(?<=\d)(?=[a-z])#i', "0982asdlkj"));
prints
Array
(
[0] => 0982
[1] => asdlkj
)
This only works if the letter part really only contains letters and no digits.
Update:
Just to clarify what is going on here:
The regular expressions looks at every position and if a digit is before that position ((?<=\d)) and a letter after it ((?=[a-z])), then it matches and the string gets split at this position. The whole thing is case-insensitive (i).
Use preg_match() with a regular expression of (\d+)([a-zA-Z]+). If you want to limit the number of digits to 1-4 and letters to 6-9, change it to (\d+{1,4})([a-zA-Z]{6,9}).
preg_match("/(\\d+)([a-zA-Z]+)/", "0982asdlkj", $matches);
print("Integer component: " . $matches[1] . "\n");
print("Letter component: " . $matches[2] . "\n");
Outputs:
Integer component: 0982
Letter component: asdlkj
http://ideone.com/SKtKs
You can also do it using preg_split by splitting your input at the point which between the digits and the letters:
list($num,$alpha) = preg_split('/(?<=\d)(?=[a-z]+)/i',$Order_num);
You can use a regex for that.
preg_match('/(\d{1,4})([a-z]+)/i', $str, $matches);
array_shift($matches);
list($num, $alpha) = $matches;
Check this out
<?php
$Order_num = "0982asdlkj";
$split=split("[0-9]",$Order_num);
$alpha=$split[(sizeof($split))-1];
$number=explode($alpha, $Order_num);
echo "Alpha -".$alpha."<br>";
echo "Number-".$number[0];
?>
with regards
wazzy
My preferred approach would be sscanf() because it is concise, doesn't need regex, offers the ability to cast the numeric segment as integer type, and doesn't generate needless fullstring matches like preg_match(). %s does rely, though, on the fact that there will be no whitespaces in the letters segment of the string.
Demo
$Order_num = "0982asdlkj";
var_export (
sscanf($Order_num, '%d%s')
);
This can also be set up to declare individual variables.
sscanf($Order_num, '%d%s', $numbers, $letters)
If wanting to use a preg_ function, preg_split() is most appropriate, but I wouldn't use expensive lookarounds. Match the digits, then forget them (with \K). This will split the string without consuming any characters. Demo
var_export (
preg_split('/\d+\K/', $Order_num)
);
To assign variables, use "symmetric array destructuring".
[$numbers, $letters] = preg_split('/\d+\K/', $Order_num);
Beyond these single function approaches, there will be MANY two function approaches like:
$numbers = rtrim($Order_num, 'a..z');
$letters = ltrim($Order_num, '0..9');
But I wouldn't use them in a professional script because they lack elegance.

Categories