25

I have a string which is combination of letters and digits. For my application i have to separate a string with letters and digits: ex:If my string is "12jan" i hav to get "12" "jan" separately..

alex
  • 479,566
  • 201
  • 878
  • 984
sandeep
  • 2,862
  • 9
  • 44
  • 54

7 Answers7

32
$numbers = preg_replace('/[^0-9]/', '', $str);
$letters = preg_replace('/[^a-zA-Z]/', '', $str);
Mike C
  • 1,808
  • 15
  • 17
  • [You don't need to invoke the regex engine twice](http://stackoverflow.com/questions/4311156/how-to-separate-letters-and-digits-from-a-string-in-php/4311202#4311202). – alex Nov 30 '10 at 07:08
  • 2
    @alex, if it's a matter of speed, what I posted is faster in my test (100000 iterations). I believe it's clearer too. – Mike C Nov 30 '10 at 07:23
  • It is faster, by about 3 times time in my tests. I'm not which one is clearer though. – alex Nov 30 '10 at 11:44
  • There are [simpler ways to express digits and non-digits in a regex pattern](https://stackoverflow.com/a/65704778/2943403). – mickmackusa Jul 23 '21 at 00:01
18

You can make use of preg_split to split your string at the point which is preceded by digit and is followed by letters as:

$arr = preg_split('/(?<=[0-9])(?=[a-z]+)/i',$str);

Code in Action

<?php
$str = '12jan';
$arr = preg_split('/(?<=[0-9])(?=[a-z]+)/i',$str);                                                               
print_r($arr);

Result:

Array
(
    [0] => 12
    [1] => jan
)
Kev
  • 118,037
  • 53
  • 300
  • 385
codaddict
  • 445,704
  • 82
  • 492
  • 529
10
$string = "12312313sdfsdf24234";
preg_match_all('/([0-9]+|[a-zA-Z]+)/',$string,$matches);
print_r($matches);

this might work alot better

Breezer
  • 10,410
  • 6
  • 29
  • 50
  • 1
    givng out put Array ( [0] => Array ( ) [1] => Array ( ) [2] => Array ( ) ) –  Nov 30 '10 at 06:47
  • Why bother with the capture grouping? I'd probably use a case insensitively flag. This answer is missing its educational explanation. – mickmackusa Jul 22 '21 at 23:55
9
preg_match_all('/^(\d+)(\w+)$/', $str, $matches);

var_dump($matches);

$day = $matches[1][0];
$month = $matches[2][0];

Of course, this only works when your strings are exactly as described "abc123" (with no whitespace appended or prepended).

If you want to get all numbers and characters, you can do it with one regex.

preg_match_all('/(\d)|(\w)/', $str, $matches);

$numbers = implode($matches[1]);
$letters = implode($matches[2]);

var_dump($numbers, $letters);

See it!

alex
  • 479,566
  • 201
  • 878
  • 984
  • 1
    This presumes that the string won't be jan12 or fg1dg34sdf. – Mike C Nov 30 '10 at 07:00
  • `preg_match_all('/(\d)|(.)|(\w)/', $str, $matches);` will also respect strings like '12-jan' or 'jan-12', if you want to reuse the extracted characters too. – MrMacvos Feb 20 '20 at 13:34
  • 1
    The commented code by MrMacvos is misleading/bad, but I cannot dv it. **Do not use it.** https://3v4l.org/9tDfr and https://3v4l.org/INJ1H – mickmackusa Jul 22 '21 at 23:52
4

You can split the string by matching sequences of digits or non-digits, then "forgetting" the matched characters with \K.

preg_split(
    '~(?:\d+|\D+)\K~',
    $string,
    0,
    PREG_SPLIT_NO_EMPTY
)

Or you could use matched digits as the delimiter and retain the delimiters in the output.

preg_split(
    '~(\d+)~',
    $string,
    0,
    PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE 
)

A demonstration of both techniques.


If you know the order of your numeric and alphabetic substrings, then sscanf() is a perfect tool.

Code: (Demo)

var_export(sscanf('12jan', '%d%s'));

Output:

array (
  0 => 12,
  1 => 'jan',
)

Notice how 12 is conveniently cast as an integer as well.

sscanf() also allows individual variables to be assigned if desired ($day and $month) as the 3rd and 4th parameters.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • This will produce many groups when the numbers and letters are interwoven. – Dharman Jul 23 '21 at 17:41
  • Of course it will. What's the alternative? The [mcve] is so narrowly scoped that I have no way to guess how the desired output should differ if the input is extended. – mickmackusa Jul 23 '21 at 22:00
2

This works for me as per my requirement, you can edit as per yours

function stringSeperator($string,$type_return){

    $numbers =array();
    $alpha = array();
    $array = str_split($string);
    for($x = 0; $x< count($array); $x++){
        if(is_numeric($array[$x]))
            array_push($numbers,$array[$x]);
        else
            array_push($alpha,$array[$x]);
    }// end for         

    $alpha = implode($alpha);
    $numbers = implode($numbers);

    if($type_return == 'number')    
    return $numbers;
    elseif($type_return == 'alpha')
    return $alpha;

}// end function
  • This answer is missing its educational explanation. Why not just use iterated string concatenating techniques if you are going to return strings? Using temporary arrays and imploding seems unnecessarily wasteful. – mickmackusa Jul 23 '21 at 00:03
-1

Try This :

$string="12jan";
$chars = '';
$nums = '';
for ($index=0;$index<strlen($string);$index++) {
    if(isNumber($string[$index]))
        $nums .= $string[$index];
    else    
        $chars .= $string[$index];
}
echo "Chars: -$chars-<br>Nums: -$nums-";


function isNumber($c) {
    return preg_match('/[0-9]/', $c);
} 
  • in some versions it is is_numeric() – Yan.D Feb 04 '18 at 21:26
  • Calling `preg_match()` inside of a custom function for EVERY character in a string -- that's WAY too much overhead for this task. I would not recommend that any researchers use this option. As a result, I have dv'ed and voted to delete this answer. – mickmackusa Jul 22 '21 at 23:25