Using regular expression subpattern to instead of

2019-09-01 01:06发布

问题:

I'm interested if its possible to make include subpattern (child pattern) into a another pattern that would allow me to convert those 2 preg_match and preg_match_all into one preg_match/preg_match_all.

<?php

$data = 'office phones tel1 6665555998 tel2 555666888 tel3 555688855 home phones tel1 555222555 tel2 555222444 tel3 555666888';

preg_match('/phones(.*)home phones/', $data, $matches); // 1st operation
preg_match_all('/[0-9]{4,12}/',  $matches[1],  $matches); // 2nd operation

var_dump($matches);

// Question is: How to get same output with just only one preg_match

preg_match('/phones(SUBPATTERN)home phones/', $data, $result_data);

// Where SUBPATTERN is a pattern that would do exactly what 2nd operation did
// so $result_data contains what does $matches (array structure can be different can be 3 dimmensional array not only 2)

Example data: https://eval.in/138817

Note: This question is another approach to get answer which had different data: PHP Regular expression return submatches as array

回答1:

You can use the \G anchor with a global research (preg_match_all):

$pattern = '~(?:office phones|\G(?!\A)) tel\d+ \K\d{4,12}~';
preg_match_all($pattern, $data, $matches);

print_r($matches);

\G is an anchor for the position in the string after the last match, when there is not yet match (at the begining) it is equivalent to the \A anchor.

\K is used to remove the left part of the match from match result.



回答2:

Use positive lookahead (?=.*?home)

<?php

$data = 'office phones tel1 6665555998 tel2 555666888 tel3 555688855 home phones tel1 555222555 tel2 555222444 tel3 555666888';
preg_match_all('/([\d]{2,})(?=.*?home)/', $data, $matches, PREG_PATTERN_ORDER);
print_r($matches[1]);

Array
(
    [0] => 6665555998
    [1] => 555666888
    [2] => 555688855
)

?>

PHP
http://ideone.com/nryjIm

REGEX
http://regex101.com/r/oV7mO2

This is an update based on your comment:

    $pnlist = "office phones tel1 6665555998 tel2 555666888 tel3 555688855 home phones tel1 555222555 tel2 555222444 tel3 555666888";

/*1*/    preg_match_all('/(?:office)(.*?)(?:home)/', $pnlist, $result, PREG_PATTERN_ORDER);
/*2*/    preg_match_all('/([\d]{2,})/', $result[1][0], $pn, PREG_PATTERN_ORDER);

    print_r($pn[1]);

/*
Array ( 
 [0] => 6665555998
 [1] => 555666888
 [2] => 555688855
 ) 
*/

You can change the first preg_match_all start(office) and ending (home) values to whatever you want, then you match the phone numbers on that group.



回答3:

$data = 'office phones tel1 6665555998 tel2 555666888 tel3 555688855 home phones tel1 555222555 tel2 555222444 tel3 555666888';


preg_match_all('/[0-9]{4,12}/', $data,  $matches); // 2nd operation

var_dump($matches);

Like this example