匹配两个特定子字符串之一之前或之后的数字子字符串

Posted

技术标签:

【中文标题】匹配两个特定子字符串之一之前或之后的数字子字符串【英文标题】:Match numeric substring which is preceded or followed by one of two specific substrings 【发布时间】:2021-12-01 11:21:03 【问题描述】:

我有一个程序从后面有CZK 的链中选择一个金额。如何编辑表达式(模式)以检查 CZK 是否在数字前面?见 string1 和 string2:

$string='Rohlík 4,99 Kč 51235';
//$string1='Rohlík CZK 4,99 51235';
//$string2='Rohlík Kč4,99 51235';

$replace = [' ', '.'];

$string = str_replace($replace,"",$string);

$string = str_replace(',',".",$string);


/*Change?*/

$pattern = '/[0-9]*[.]?[0-9]*[Kč,CZK]/';
preg_match($pattern, $string, $matches); // => 4.99 Kč
$string = $matches;

$pattern = '/[0-9]*[.]?[0-9]*/';
preg_match($pattern, $string[0], $matches);

$price = $matches[0];
print_r($price); // => 4.99

【问题讨论】:

非捕获组:(?: ) 和交替:| debuggex.com/r/RqjVlY2tm3ym8HYt [Kč,CZK]匹配其中一个字符,而不是单词,尝试:(Kč|CZK)。它匹配CZK “字符类”中列出的字符不应重复。 【参考方案1】:

在您的模式中使用逻辑分组来匹配可能出现在目标数字之前或之后的标签(可以在此步骤之后用点替换逗号)。

代码:(Demo)

$strings = [
    'Rohlík 4,99 Kč 51235',
    'Rohlík CZK 4,99 51235',
    'Rohlík Kč4,99 51235',
    'Rohlík foo4,99 51235'
];

foreach ($strings as $string) 
    var_export(
        preg_match('/\b(?:(?:Kč|CZK) ?\K\d+(?:,\d+)?|\d+(?:,\d+)?(?= ?(?:Kč|CZK)))\b/u', $string, $m)
        ? $m[0]
        : 'not found'
    );
    echo "\n";

输出:

'4,99'
'4,99'
'4,99'
'not found'

模式细分:

/                     #starting pattern delimiter
  \b                  #word boundary to guarantee matching the whole label
  (?:                 #start non-capturing group 1
    (?:Kč|CZK) ?      #non-capturing group 2 requiring one of two labels, optionally followed by a space
    \K                #forget all previously matched characters
    \d+(?:,\d+)?      #match the targeted integer/float value with comma as decimal placeholder
    |                 #OR
    \d+(?:,\d+)?      #match the targeted integer/float value with comma as decimal placeholder
    (?= ?(?:Kč|CZK))  #lookahead to for optional space followed by one of the two labels
  )                   #close non-capturing group 1
  \b                  #word boundary to guarantee matching the whole label
/                     #ending pattern delimiter
u                     #unicode/multi-byte flag

【讨论】:

你对我的帖子是正确的 - 我删除了它。您应该在数字前后允许逗号或句点以及可能的空格。 我的模式确实允许数字前后的可选空格。来自 OP 的示例输入不包括使用点的浮点数。我假设这是他们首选的输出格式,而不是稳定输入的方式。如果输入中可能出现点,则可以将, 更改为[,.] 确实如此。对于不区分大小写的i,他应该没问题。 再次,示例输入并不表示需要不区分大小写的标志。可能是,但只有 OP 知道这一点。

以上是关于匹配两个特定子字符串之一之前或之后的数字子字符串的主要内容,如果未能解决你的问题,请参考以下文章

求字符串不同子串个数

在特定单词之后从字符串中获取子字符串

正则表达式匹配字母数字,除了特定的子字符串

5.2.1 正则表达式语法与子模式扩展语法

两个字符串的所有公共最长子序列

字符串匹配----后缀数组算法