6

Consider the following strings:

$strings = array(
    "8.-10. stage",
    "8. stage"
);

I would like to extract the first integer of each string, so it would return

8
8

I tried to filter out numbers with preg_replace but it returns all integers and I only want the first.

foreach($strings as $string)
{
    echo preg_replace("/[^0-9]/", '',$string);
}

Any suggestions?

Fredrik
  • 1,741
  • 4
  • 24
  • 40

7 Answers7

25

A convenient (although not record-breaking in performance) solution using regular expressions would be:

$string = "3rd time's a charm";

$filteredNumbers = array_filter(preg_split("/\D+/", $string));
$firstOccurence = reset($filteredNumbers);
echo $firstOccurence; // 3

Assuming that there is at least one number in the input, this is going to print the first one.

Non-digit characters will be completely ignored apart from the fact that they are considered to delimit numbers, which means that the first number can occur at any place inside the input (not necessarily at the beginning).

If you want to only consider a number that occurs at the beginning of the string, regex is not necessary:

echo substr($string, 0, strspn($string, "0123456789"));
Pepijn Olivier
  • 927
  • 1
  • 18
  • 32
Jon
  • 428,835
  • 81
  • 738
  • 806
  • 1
    the "reset" example results in PHP Strict Notices... "Strict Standards: Only variables should be passed by reference" – Kyle Anderson Aug 18 '15 at 06:11
  • How can I do this if I only want to return the alphabet? – xjshiya Mar 06 '19 at 08:10
  • @xjshiya check out this answer here https://stackoverflow.com/questions/6067592/regular-expression-to-match-only-alphabetic-characters/6067604 – Tami Oct 08 '21 at 14:20
  • I would never use this in a professional application or anywhere else for that matter. `array_filter` will destriy a zero value and this task can be done in one function call instead of 3. – mickmackusa Aug 07 '22 at 03:44
9
preg_match('/\d+/',$id,$matches);
$id=$matches[0];
MERT DOĞAN
  • 2,864
  • 26
  • 28
8

If the integer is always at the start of the string:

(int) $string;

If not, then strpbrk is useful for extracting the first non-negative number:

(int) strpbrk($string, "0123456789");

Alternatives

These one-liners are based on preg_split, preg_replace and preg_match:

preg_split("/\D+/", " $string")[1];
(int) preg_replace("/^\D+/", "", $string);
preg_match('/\d+/', "$string 0", $m)[0];

Two of these append extra character(s) to the string so empty strings or strings without numbers do not cause problems.

Note that these alternative solutions are for extracting non-negative integers only.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • 1
    `(int) $string;` is a lovely solution, I've never come across that – Sam Holguin Nov 23 '20 at 21:51
  • 1
    @mickmackusa, thanks for your review. The `preg_split` based solution had the additional space at the wrong side. Now corrected. The `strpbrk` solution is fine though: it was never intended to work without the `(int)` cast, so you should keep it in. – trincot Aug 07 '22 at 07:03
2

Try this:

$strings = array(
    "8.-10. stage",
    "8. stage"
);

$res   = array();
foreach($strings as $key=>$string){
  preg_match('/^(?P<number>\d)/',$string,$match);
  $res[$key] = $match['number'];
}

echo "<pre>";
print_r($res);
Prasanth Bendra
  • 31,145
  • 9
  • 53
  • 73
  • 2
    But only works for numbers with one digit at the start of the string, and if there is none, the line after causes an error. – trincot Feb 08 '16 at 22:30
  • 1
    The named capture group is needless pattern bloat because you are using the fullstring match anyway. As trincot said, this will ONLY work when the number is at the start of the string. – mickmackusa Aug 07 '22 at 03:56
1
foreach($strings as $string){
 if(preg_match("/^(\d+?)/",$string,$res)) {
   echo $res[1].PHP_EOL;
 }
}
realization
  • 587
  • 1
  • 4
  • 5
  • The capture group is not necessary/beneficial. The lazy quantifier is not necessary/beneficial. This answer is missing its educational explanation. – mickmackusa Aug 07 '22 at 03:54
1

if you have Notice in PHP 7 +

Notice: Only variables should be passed by reference in YOUR_DIRECTORY_FILE.php on line LINE_NUMBER

By using this code

echo reset(array_filter(preg_split("/\D+/", $string)));

Change code to

$var = array_filter(preg_split("/\D+/", $string));
return reset($var);

And enjoy! Best Regards Ovasapov

Arthur Hovasap
  • 225
  • 1
  • 2
  • 7
1

How to filter out all characters except for the first occurring whole integer:

It is possible that the target integer is not at the start of the string (even if the OP's question only provides samples that start with an integer -- other researchers are likely to require more utility ...like the pages that I closed today using this page). It is also possible that the input contains no integers, or no leading / no trailing non-numeric characters.

The following is a regex expression has two checks:

  1. It targets all non-numeric characters from the start of the string -- it stops immediately before the first encountered digit, if there is one at all.
  2. It matches/consumes the first encountered whole integer, then immediatelly forgets/releases it (using \K) before matching/consuming ANY encountered characters in the remainder of the string.

My snippet will make 0, 1, or 2 replacements depending on the quality of the string.

Code: (Demo)

$strings = [
    'stage', // expect empty string
    '8.-10. stage', // expect 8
    '8. stage', // expect 8
    '8.-10. stage 1st', // expect 8
    'Test 8. stage 2020', // expect 8
    'Test 8.-10. stage - 2020 test', // expect 8
    'A1B2C3D4D5E6F7G8', // expect 1
    '1000', // expect 1000
    'Test 2020', // expect 2020
];

var_export(
    preg_replace('/^\D+|\d+\K.*/', '', $strings)
);

Or: (Demo)

preg_replace('/^\D*(\d+).*/', '$1', $strings)

Output:

array (
  0 => '',
  1 => '8',
  2 => '8',
  3 => '8',
  4 => '8',
  5 => '8',
  6 => '1',
  7 => '1000',
  8 => '2020',
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136