tags:

views:

69

answers:

3

I want to retrieve the consecutive 8 digits out of a string.

"hello world,12345678anything else"

should return 12345678 as result(the space in between is optional).

But this should not return anything:

"hello world,123456789anything else"

Because it has 9 digits,I only need 8 digits unit.

+7  A: 

Try

'/(?<!\d)\d{8}(?!\d)/'
S.Mark
Can you elaborate what `(?<!\d)` and `(?!\d)` mean?
@user198729, those are look behind, and look ahead, `!` mean not, so \d shouldn't come before and after of \d{8}, for more info, see http://www.regular-expressions.info/lookaround.html
S.Mark
These are referred to as "zero-width look-around assertions". There's a whole class of RE atoms that start with `(?`; the ones in this example are followed by `!`, to indicate that they match what's coming up as long as it doesn't match what's after the `!`, or `<!`, to indicate that they match negatively against what just passed. So `(?<!\d) will match at any point in the string that doesn't immmediately follow a numeric digit. They are called 'zero-width' because they don't actually add anything to the match.
intuited
More precisely,`(?<!\d)` is look ahead,and `(?!\d)` behind,right?
@user198729, thats opposite
S.Mark
@S.Mark,I found.But why?It's opposite to the intuitive,isn't it?
@user198729, I mean, `(?<!\d)` is look behind and `(?!\d)` is look ahead
S.Mark
Yes,that's why I say it's counter intuitive.`(?<!\d)` is positioned **ahead** but called **look behind**
yeah it's like a rear-view mirror.
intuited
@user198729, Imm, sorry I dont get it, `(?<!\d)` is positioned behind `\d{8}` in my eye.
S.Mark
Yeah it matches anything (or nothing) that **isn't** a digit. `(?<=\d)` would match anything that is. Note that (?<=\D) doesn't work in this situation because it will only match if there's something there, ie not at the beginning of the string or line.
intuited
A: 
$var = "hello world,12345678798anything else";
preg_match('/[0-9]{8}/',$var,$match);
echo $match[0];
muruga
There is already a solution almost exactly like this which we have determined doesn't work.
animuson
A: 

You need to match the stuff on either side of the 8 digits. You can do this with zero-width look-around assertions, as exemplified by @S Mark, or you can take the simpler route of just creating a backreference for the 8 digits:

preg_match('/\D(\d{8})\D/', $string, $matches)
$eight_digits = $matches[1];

But this won't match when the digits start or end a line or string; for that you need to elaborate it a bit:

preg_match('/(?:\D|^)(\d{8})(?:\D|$)/', $string, $matches)
$eight_digits = $matches[1];

The (?:...) in this one allows you to specify a subset of alternates, using |, without counting the match as a back-reference (ie adding it to the elements in the array $matches).

For many more gory details of the rich and subtle language that is Perl-Compatible Regular Expression syntax, see http://ca3.php.net/manual/en/reference.pcre.pattern.syntax.php

intuited