尝试根据用户定义的模式从字符串中提取子字符串

时间:2014-04-25 20:13:41

标签: php regex

我试图弄清楚如何使用用户定义的模式从字符串中提取日期。该模式可以采用多种不同的方式,例如:Y-m-dd/m/Y(m/d/Y)[d/m/Y]等等。

包含其中解析日期的字符串是常规文本块,并使用定义的模式进行解析(类似于上面描述的)。例如,字符串中的日期类似于以下内容,具体取决于用户定义的模式:2014-04-2504/25/201425/04/2014(04/25/2014),{{1等等。

有没有办法使用用户定义的模式从字符串中提取实际日期?我希望某种正则表达式可以完成这项工作,但到目前为止,我仍然坚持这个问题。

3 个答案:

答案 0 :(得分:1)

你可以强制一种模式策略,即年份总是4个字符等。YYYY-MM-DDstr_replace()来获得你想要的一个。您可能需要使用大写字母,否则\d会获得替换,因为它会看到d。或者更好的是,强制模式为大写:

$pattern = 'Y-M-D';
$pattern = str_replace(array('Y','M','D'), array('\d{4}','\d{1,2}','\d{1,2}'), strtoupper($pattern));
$pattern = preg_quote($pattern, '#');
preg_match("#$pattern#", $string, $match);

print_r($match);

答案 1 :(得分:0)

创建一个映射,将日期模式转换为正则表达式,然后使用preg_match_all()从给定字符串中提取所有匹配日期:

function extractDates($text, $pattern) 
{
    $mapping = [
        'y' => '\d{4}',
        'm' => '\d{2}',
        'd' => '\d{2}',
    ];

    $regex = strtr(strtolower($pattern), $mapping);

    if (preg_match_all("~$regex~", $text, $matches)) {
        return $matches[0];
    }

    return false;
}

测试用例:

$testcases = [
    'foo 2014-04-25 bar'   => 'y-m-d',
    'foo 25/04/2014 bar'   => 'd/m/y',
    'foo 04/25/2014 bar'   => 'm/d/y',
    'foo [2014-04-25] bar' => 'y-m-d',
    'foo (25/04/2014) bar' => 'd/m/y',
    'foo [04/25/2014] bar' => 'm/d/y',
];

foreach ($testcases as $text => $pattern) {
    echo extractDates($text, $pattern)[0], PHP_EOL;
}

<强>输出:

2014-04-25
25/04/2014
04/25/2014
2014-04-25
25/04/2014
04/25/2014

Demo

答案 2 :(得分:0)

可以使用用户可用于定义其选择格式的预定义符号来完成。然后,您可以使用这些符号安全地创建正则表达式:

function findDates($haystack, $format) {

    // Symbol to regex table
    // Change this to suit how you want the symbols
    // to be matched
    static $table = [
        'D' => '(?<!\d)(?:0[1-9]|[12]\d|3[01])(?!\d)',
        'd' => '(?<!\d)(?:[1-9]|[12]\d|3[01])(?!\d)',
        'M' => '(?<!\d)(?:0[1-9]|1[012])(?!\d)',
        'm' => '(?<!\d)(?:[1-9]|1[012])(?!\d)',
        'Y' => '(?<!\d)(?:\d{4})(?!\d)',
        'y' => '(?<!\d)(?:\d{2})(?!\d)',
    ];
    // Escape any special characters in the format, so
    // that it can be used for the regular expression
    $format = preg_quote($format, '/');

    // Create the regex by replacing symbols with their
    // corresponding regex
    $regex = str_replace(array_keys($table), array_values($table), $format);

    // Attempt to find dates
    preg_match_all("/{$regex}/", $haystack, $matches);

    // Return matches; if there were no matches then
    // then return false instead
    return $matches[0] ?: false;
}
$text = 'It happens on either 18/9 2015 or 8/10 2015.';
$findFormat = 'd/m Y';
var_dump(findDates($text, $findFormat));