php: split string until first occurance of a number - php

i have string like
cream 100G
sup 5mg Children
i want to split it before the first occurrence of a digit. so the result should be
array(
array('cream','100G'),
array('sup','5mg Children')
);
can so one tell me how to create pattern for this ?
i tried
list($before, $after) = array_filter(array_map('trim',
preg_split('/\b(\d+)\b/', $t->formula)), 'strlen');
but something went wrong.

Try this:
<?php
$first_string = "abc2 2mg";
print_r( preg_split('/(?=\d)/', $first_string, 2));
?>
Will output:
Array ( [0] => abc [1] => 2 2mg )

The regular expression solution would be to call preg_split as
preg_split('/(?=\d)/', $t->formula, 2)
The main point here is that you do not consume the digit used as the split delimiter by using positive lookahead instead of capturing it (so that it remains in $after) and that we ensure the split produces no more than two pieces by using the third argument.

You don't need regular expressions for that:
$str = 'cream 100g';
$p = strcspn($str, '0123456789');
$before = substr($str, 0, $p);
$after = substr($str, $p);
echo "before: $before, after: $after";
See also: strcspn()
Returns the length of the initial segment of $str which does not contain any of the characters in '0123456789', aka digits.

Related

highlight last 3 number in the string

how to highlight last 3 number in the string:
ab9c5lek94ke72koe8nsk9
i want output:
ab9c5lek94ke72koe8nsk9
i tried following:
$str = "ab9c5lek94ke72koe8nsk9";
$numbers = preg_replace('/[^0-9]/', '', $str );
$last3 = substr($numbers, -3);
$highlights = str_split($last3);
$output = preg_replace('/'.implode('|', $highlights).'/i', '<b>$0</b>', $str);
but it highlight:
ab9c5lek94ke72koe8nsk9
You can achieve that easily using regular expression with PHP's preg_replace() function. Just find last 3 digits 3 times at the end of the string. See the following code:
$str1 = 'ab9c5lek94ke2koe8nsk9';
$str2 = 'dag2vue41a89au76zhz30';
echo preg_replace('/(\d)([^\d]*)(\d)([^\d]*)(\d)([^\d]*)$/mui', '<b>$1</b>$2<b>$3</b>$4<b>$5</b>$6', $str1);
echo preg_replace('/(\d)([^\d]*)(\d)([^\d]*)(\d)([^\d]*)$/mui', '<b>$1</b>$2<b>$3</b>$4<b>$5</b>$6', $str2);
Outputs
ab9c5lek94ke2koe8nsk9
and
dag2vue41a89au76zhz30
You can have a regex like below:
/(\d)([^\d]*)(\d)([^\d]*)(\d)([^\d]*)$/
which is basically (\d)([^\d]*) 3 times with a $ sign at the end. It means we are matching a digit followed by 0 or more non digit characters. Note that we do need the $ sign at the end to match only last 3 digits.
Snippet:
<?php
$str = "ab9c5lek94ke2koe8nsk9";
echo preg_replace('/(\d)([^\d]*)(\d)([^\d]*)(\d)([^\d]*)$/',"<b>$1</b>$2<b>$3</b>$4<b>$5</b>$6",$str);
Demo: https://3v4l.org/PoYCG
The replacement string is just having the bold tags with group number of the matched strings which are to be highlighted.
You can split the string on the 3rd from last number, then highlight everything in that sub string and then recombine the substrings.
In my example, I get all of the numbers in the string and put them in array. Then I use that array to get the delimiter (72 in your example), then use that to split the string into two arrays, at that point you can highlight everything in array[1] and then combine it back into array[0]
$str = "ab9c5lek94ke72koe8nsk9";
// get all of the numbers in order and place into it's own array
$numbers = trim(preg_replace('/[^0-9]/', ' ', $str ));
$numbers = preg_split('/\s+/', $numbers);
// using that get the delimiter to where to split the string. and split.
$delim = $numbers[count($numbers)-3];
$arr = explode($delim, $str);
$arr[1] = $delim . $arr[1];
// then highlight everything in $arr[1]
// then combine $arr[0] and $arr[1]

php regex replace each character with asterisk

I am trying to something like this.
Hiding users except for first 3 characters.
EX)
apple -> app**
google -> goo***
abc12345 ->abc*****
I am currently using php like this:
$string = "abcd1234";
$regex = '/(?<=^(.{3}))(.*)$/';
$replacement = '*';
$changed = preg_replace($regex,$replacement,$string);
echo $changed;
and the result be like:
abc*
But I want to make a replacement to every single character except for first 3 - like:
abc*****
How should I do?
Don't use regex, use substr_replace:
$var = "abcdef";
$charToKeep = 3;
echo strlen($var) > $charToKeep ? substr_replace($var, str_repeat ( '*' , strlen($var) - $charToKeep), $charToKeep) : $var;
Keep in mind that regex are good for matching patterns in string, but there is a lot of functions already designed for string manipulation.
Will output:
abc***
Try this function. You can specify how much chars should be visible and which character should be used as mask:
$string = "abcd1234";
echo hideCharacters($string, 3, "*");
function hideCharacters($string, $visibleCharactersCount, $mask)
{
if(strlen($string) < $visibleCharactersCount)
return $string;
$part = substr($string, 0, $visibleCharactersCount);
return str_pad($part, strlen($string), $mask, STR_PAD_RIGHT);
}
Output:
abc*****
Your regex matches all symbols after the first 3, thus, you replace them with a one hard-coded *.
You can use
'~(^.{3}|(?!^)\G)\K.~'
And replace with *. See the regex demo
This regex matches the first 3 characters (with ^.{3}) or the end of the previous successful match or start of the string (with (?!^)\G), and then omits the characters matched from the match value (with \K) and matches any character but a newline with ..
See IDEONE demo
$re = '~(^.{3}|(?!^)\G)\K.~';
$strs = array("aa","apple", "google", "abc12345", "asdddd");
foreach ($strs as $s) {
$result = preg_replace($re, "*", $s);
echo $result . PHP_EOL;
}
Another possible solution is to concatenate the first three characters with a string of * repeated the correct number of times:
$text = substr($string, 0, 3).str_repeat('*', max(0, strlen($string) - 3));
The usage of max() is needed to avoid str_repeat() issue a warning when it receives a negative argument. This situation happens when the length of $string is less than 3.

Is is possible to know the position of a match in a subject string

I have a file name where information has to be replaced. Here is a subject sample :
FileA-2014-11-01_K_1_A2_383.xxx
As many files are to be processed, this filename is first matched by a regex, say :
/[a-zA-Z]*-\d{4}-\d{2}-\d{2}_(\w)_(\d)_A2_(\d*)\.xxx$/
This regex will give me, using preg_match, the values to be replaced, here :
K=>A
1=>2
383=>666
My first try was to naively use "str_replace", but it fails when patterns are repeated in the string : here i will get :
FileA-2024-22-02_A_2_A2_666.xxx
So the date is also modified by the str_replace (as it was told to do..)
So, i wonder if there is a way to know where is a given match in the string to have a clean replacement.
I'm now trying to revert the regex to be able to capture non-replacement blocks, and then insert replaced data. That regex would be :
/([a-zA-Z]*-\d{4}-\d{2}-\d{2}_)\w(_)\d(_A2_)\d*(\.xxx)$/
With that one, i'm able to keep non-replaced parts. I now have to find a kind of index to know the replacement position in the string. I guess I can achieve this way, but is seems somewhat complicated and error prone.
Given I only have the initial regex and the map for to=>from replacement, is there a way to do that in a better way?
[EDIT : solution]
<?php
$filename = "FileA-2014-11-01_K_1_A2_383.xxx";
$expected = "FileA-2014-11-01_A_2_A2_666.xxx";
$regex = "/[a-zA-Z]*-\d{4}-\d{2}-\d{2}_(\w)_(\d)_A2_(\d*)\.xxx$/";
global $replacements;
$replacements["K"] = "A";
$replacements["1"] = "2";
$replacements["383"] = "666";
$result = preg_replace_callback($regex, function($matches){
global $replacements;
print_r($matches);
// ended here. no way.
}, $filename);
if(strcmp($result,$expected)==0)
echo "preg_replace_callback() : Yep\n";
else
echo "preg_replace_callback() : Nop\n";
preg_match($regex, $filename, $matches, PREG_OFFSET_CAPTURE);
// remove useless global string match
array_shift($matches);
$result = $filename;
foreach($matches as $matchInfo){
$match = $matchInfo[0];
$position = $matchInfo[1];
$matchLength= strlen($match);
$beforeReplacementPart = substr($result, 0, $position);
$afterReplacementPart = substr($result, ($position + $matchLength));
$result = $beforeReplacementPart . $replacements[$match] . $afterReplacementPart;
}
if(strcmp($result,$expected)==0)
echo "preg_match() and substr game : Yep\n";
else
echo "preg_match() and substr game : Nop\n";
A regex that matches that filename:
$re = '/[a-zA-Z]*-\d{4}-\d{2}-\d{2}_(\w)_(\d)_A2_(\d*)\.xxx$/';
$str = 'FileA-2014-11-01_K_1_A2_383.xxx';
If you add PREG_OFFSET_CAPTURE as the fourth parameter ($flags) to the call to preg_match(), it will also return the offset of each captured string in the third parameter:
preg_match($re, $str, $matches, PREG_OFFSET_CAPTURE);
A print_r($matches) will reveal:
Array
(
[0] => Array
(
[0] => FileA-2014-11-01_K_1_A2_383.xxx
[1] => 0
)
[1] => Array
(
[0] => K
[1] => 17
)
[2] => Array
(
[0] => 1
[1] => 19
)
[3] => Array
(
[0] => 383
[1] => 24
)
)
$matches[0] is the part that matched the entire regex. $matches[1] is the first capturing sub-expression, $matches[2] is the second and so on.
$matches[1][0] is the fragment from the input string that matched the first regex sub-expression (\w) and $matches[1][1] is the offset in the input string where it was found. The same for $matches[N][0] and $matches[N][1] for the Nth sub-expression.
If you need to do a simple replacement then you don't need to bother about offsets but use preg_replace() or, if the replacement expression is complex or dynamic, preg_replace_callback().
Using preg_replace() you need to capture the parts you want to keep:
$re = '/([a-zA-Z]*-\d{4}-\d{2}-\d{2}_)\w_\d_A2_\d*(\.xxx)$/';
$str = 'FileA-2014-11-01_K_1_A2_383.xxx';
$new = preg_replace($re, '$1A_2_A2_666$2', $str);
echo($new."\n");
In the replacement string, $1 and $2 denote the sub-expressions from the regex. We marked them for capturing in order to re-use them in the replacement string.
At least preg_match_all() offers the option
PREG_OFFSET_CAPTURE
If this flag is passed, for every occurring match the appendant string offset will also be returned. Note that this changes the value of matches into an array where every element is an array consisting of the matched string at offset 0 and its string offset into subject at offset 1.
You could try the below regex.
([a-zA-Z]*-\d{4}-\d{2}-\d{2}(?:-\d*)?_)\w_\d(_A2)_\d*(\.xxx)$
Then replace the match with
\1A_2\2_666\3
DEMO
$re = "~([a-zA-Z]*-\\d{4}-\\d{2}-\\d{2}(?:-\\d*)?_)\\w_\\d(_A2)_\\d*(\\.xxx)$~m";
$str = "FileA-2014-11-01_K_1_A2_383.xxx";
$subst = "\1A_2\2_666\3";
$result = preg_replace($re, $subst, $str);
You can use:
$re = "/([a-zA-Z]+-\\d{4}-\\d{2}-\\d{2}_)\\w+_\\d+(_A2_)\\d+(\\.xxx)$/m";
$str = "FileA-2014-11-01_K_1_A2_383.xxx";
$subst = "${1}A_2${2}666${3}";
$result = preg_replace($re, $subst, $str);
//=> FileA-2014-11-01_A_2_A2_666.xxx
RegEx Demo
Perhaps it is possible to use this in your case:
$str = strtr($str, array('_K_1_'=>'_A_2_', '_383.'=>'_666.'));
or
$str = str_replace('_K_1_A2_383.xxx', '_A_2_A2_666.xxx', $str);
So there is no more ambiguity and the replacement is fast.

Cut string from end to specific char in php

I would like to know how I can cut a string in PHP starting from the last character -> to a specific character. Lets say I have following link:
www.whatever.com/url/otherurl/2535834
and I want to get 2535834
Important note: the number can have a different length, which is why I want to cut out to the / no matter how many numbers there are.
Thanks
In this special case, an url, use basename() :
echo basename('www.whatever.com/url/otherurl/2535834');
A more general solution would be preg_replace(), like this:
<----- the delimiter which separates the search string from the remaining part of the string
echo preg_replace('#.*/#', '', $url);
The pattern '#.*/#' makes usage of the default greediness of the PCRE regex engine - meaning it will match as many chars as possible and will therefore consume /abc/123/xyz/ instead of just /abc/ when matching the pattern.
Use
explode() AND end()
<?php
$str = 'www.whatever.com/url/otherurl/2535834';
$tmp = explode('/', $str);
echo end ($tmp);
?>
Working Demo
This should work for you:
(So you can get the number with or without a slash, if you need that)
<?php
$url = "www.whatever.com/url/otherurl/2535834";
preg_match("/\/(\d+)$/",$url,$matches);
print_r($matches);
?>
Output:
Array ( [0] => /2535834 [1] => 2535834 )
With strstr() and str_replace() in action
$str = 'www.whatever.com/url/otherurl/2535834';
echo str_replace("otherurl/", "", strstr($str, "otherurl/"));
strstr() finds everything (including the needle) after the needle and the needle gets replaced by "" using str_replace()
if your pattern is fixed you can always do:
$str = 'www.whatever.com/url/otherurl/2535834';
$tmp = explode('/', $str);
echo $temp[3];
Here's mine version:
$string = "www.whatever.com/url/otherurl/2535834";
echo substr($string, strrpos($string, "/") + 1, strlen($string));

Remove the end of a string with a varying string length using PHP

Using PHP I have an array that return this data for an image:
Array
(
[0] => http://website.dev/2014/05/my-file-name-here-710x557.png
[1] => 710
[2] => 557
[3] => 1
)
Based on the demo data above, I need to somehow turn this image URL into:
http://website.dev/2014/05/my-file-name-here.png removing the -710x557 from the string.
Some things to keep in mind are:
The file extension can change and be any type of file type
710x557 might not ALWAYS be a 3 digit x 3 digit number. It could be 2 or 4
The reason I mention this is to show I cannot simply use PHP's string functions to remove the last 12 characters in the string and then add the file extension back because the last string characters could possibly be between 10 and 14 characters long sometimes and not always 12.
I was hoping to avoid a heavy regular expression code but if that is the only or best way here then I say go with it.
How do I write a regex that removes the end of a string that could have a varying length in PHP?
You can use a regex like this:
-\d+x\d+(\.\w+)$
Working demo
The code you can use is:
$re = "/-\\d+x\\d+(\\.\\w+)$/";
$str = "http://website.dev/2014/05/my-file-name-here-710x557.png";
$subst = '\1';
$result = preg_replace($re, $subst, $str, 1);
The idea is to match the resolution -NumbersXNumbers using -\d+x\d+ (that we'll get rid of it) and then capture the file extension by using (\.\w+)$ using capturing group. Check the substitution section above.
As long as it is 2 sets of digits with an 'x' in the middle preceded by a dash you can use this regex:
-[\d]*x[\d]*
$string = 'http://website.dev/2014/05/my-file-name-here-710x557.png';
$pattern = '/-[\d]*x[\d]*/';
$replacement = '';
echo preg_replace($pattern, $replacement, $string);
http://phpfiddle.org/lite/code/eh40-6d1x
You can probably use strrpos in the following manner to do this:
$str = substr($str, 0, strrpos($str, '-')) . substr($str, strrpos($str, '.'));
You can use this regex based code:
$str = "http://website.dev/2014/05/my-file-name-here-710x557.png";
$re = '/-([^-]+)(?=\.[^-]*$)/';
$result = preg_replace($re, '', $str, 1);
//=> http://website.dev/2014/05/my-file-name-here.png
RegEx Demo
$newsrc = preg_replace('#\-\d+x\d+(\.\w+$)#', '$1', $arr[0]);
see http://ideone.com/ZsELQ0

Categories