PHP中的模式匹配函数

PHP中的模式匹配函数,php,pattern-matching,Php,Pattern Matching,我正在寻找一个函数,类或函数集合,将有助于模式匹配字符串的过程,因为我有一个项目,需要大量的模式匹配,我想更容易阅读和维护比原始preg_替换(或正则周期) 我提供了一个伪示例,希望它能帮助您理解我的问题 $subject = '$2,500 + $550 on-time bonus, paid 50% upfront ($1,250), 50% on delivery ($1,250 + on-time bonus).'; $pattern = '$n,nnn'; pattern_match(

我正在寻找一个函数,类或函数集合,将有助于模式匹配字符串的过程,因为我有一个项目,需要大量的模式匹配,我想更容易阅读和维护比原始preg_替换(或正则周期)

我提供了一个伪示例,希望它能帮助您理解我的问题

$subject = '$2,500 + $550 on-time bonus, paid 50% upfront ($1,250), 50% on delivery ($1,250 + on-time bonus).';
$pattern = '$n,nnn';
pattern_match($subject, $pattern, 0);
将返回“2500美元”

将返回一个包含以下值的数组:[$2500]、$1250]、$1250]

正如我试图写的那样,这个函数使用“n”表示数字,“c”表示小写字母,“c”表示大写字母,其中任何非字母数字字符都表示它自己


任何帮助都将不胜感激。

尽管您需要使用正则表达式模式进行模式匹配,但您正在寻找的函数是。

更新:这是一个不完整的答案,不适用于多个测试模式。有关更好的解决方案,请参见@Frosty Z的答案

<?php
    function pattern_match($s, $p, $c=0) {
        $tokens = array(
            '$' => '\$',
            'n' => '\d{1}',
            'c' => '[a-z]{1}',
            'C' => '[A-Z]{1}'
        );
        $reg = '/' . str_replace(array_keys($tokens), array_values($tokens), $p) . '/';
        if ($c == 0) {
            preg_match($reg, $s, $matches);
        } else {
            preg_match_all($reg, $s, $matches);
        }
        return $matches[0];
    }

    $subject = "$2,500 + $550 on-time bonus, paid 50% upfront ($1,250), 50% on delivery ($1,250 + on-time bonus).";

    $pattern = '$n,nnn';
    print_r(pattern_match($subject, $pattern, 0));
    print_r(pattern_match($subject, $pattern, 1));

    $pattern = 'cc-cccc';
    print_r(pattern_match($subject, $pattern));
    print_r(pattern_match($subject, $pattern, 1));
?>

注意:
$模式包含
$
时,请确保对其使用单引号,否则PHP将尝试将其解析为
$变量

抱歉,但这是regex的问题。我理解你的反对意见,但在这种情况下,没有其他方法比这更有效、更简单。这是一个非常简单的匹配问题。您可以像jnpcl演示的那样编写自定义包装器,但这只会涉及更多代码和更多潜在陷阱。更不用说额外的开销。

这里是一个不带regexp的函数,应该可以工作(“C”和“C”只识别ascii字符),请享受:

<?php

// $match_all = false: returns string with first match
// $match_all = true:  returns array of strings with all matches

function pattern_match($subject, $pattern, $match_all = false)
{
  $pattern = preg_quote($pattern, '|');

  $ar_pattern_replaces = array(
      'n' => '[0-9]',
      'c' => '[a-z]',
      'C' => '[A-Z]',
    );

  $pattern = strtr($pattern, $ar_pattern_replaces);

  $pattern = "|".$pattern."|";

  if ($match_all)
  {
    preg_match_all($pattern, $subject, $matches);
  }
  else
  {
    preg_match($pattern, $subject, $matches);
  }

  return $matches[0];
}

$subject = '$2,500 + $550 on-time bonus, paid 50% upfront ($1,250), 50% on delivery ($1,250 + on-time bonus).';
$pattern = '$n,nnn';

$result = pattern_match($subject, $pattern, 0);
var_dump($result);

$result = pattern_match($subject, $pattern, 1);
var_dump($result);
函数模式匹配($subject、$pattern、$result\u作为数组){
$pattern_len=strlen($pattern);
if($pattern\u len==0)返回false;//错误:空模式
//用规则的符号('n'、'c'或'c')翻译$subject
$translate='';
$subject_len=strlen($subject);

对于($i=0;$i=48)&&($ord=65)&($ord=97)&($ordIt)可能最好创建一个函数,将其解释为正则表达式,然后按照您的需要格式化返回的数组。其他方法会慢得多……所以简化的正则表达式包装器?接下来,您需要
n{from=2,to=4}
($|¥|€)
等,您将开发正则表达式匹配的“Smarty”。您确定要走这条路线吗?您的线路«$pattern=“$n,nnn”;»是不正确的,因为$n不是一个可用的变量,它应该是:«$pattern='$n,nnn';»@freeyedboy:我知道你大部分是在开玩笑,但实际上我并不恨这个想法,就像我恨smarty一样。我觉得正则表达式不直观,因为我没有经常使用它来发展对它的亲密,甚至是基本的理解如果不以效率和速度为代价的话,易读且用户友好的格式不会是一件坏事。OP似乎想创建自己的模式。他明确表示他不想使用正则表达式。可以编写一个包装器,将他更简单的模式转换为正则表达式(例如,
stru replace('n','0-9]',$pattern);
),但除了完全重新发明正则表达式轮子之外,这就是他必须使用的。对不起,它不适用于
cc/cc
(错误)或
n.nnn
(返回'2.500',但也返回'2500','2#500'…)@Frosty Z:是的,我在出去吃午饭之前急急忙忙想得到一个答案。@Gumbo:当时感觉是个好主意?没问题,有时候我的“快速回答”也有一些缺陷:-)关于Gumbo的评论,事实上
[a-Z]{1}
相当于
[a-Z]
所以添加
{1}
似乎没有必要。很好!但是为什么在最后一个while循环中
if($n>10)exit();
呢?+1,肯定比我的有所改进。直到现在我才意识到
preg_quote()
$2,500

Array
(
    [0] => $2,500
    [1] => $1,250
    [2] => $1,250
)

on-time

Array
(
    [0] => on-time
    [1] => on-time
)
<?php

// $match_all = false: returns string with first match
// $match_all = true:  returns array of strings with all matches

function pattern_match($subject, $pattern, $match_all = false)
{
  $pattern = preg_quote($pattern, '|');

  $ar_pattern_replaces = array(
      'n' => '[0-9]',
      'c' => '[a-z]',
      'C' => '[A-Z]',
    );

  $pattern = strtr($pattern, $ar_pattern_replaces);

  $pattern = "|".$pattern."|";

  if ($match_all)
  {
    preg_match_all($pattern, $subject, $matches);
  }
  else
  {
    preg_match($pattern, $subject, $matches);
  }

  return $matches[0];
}

$subject = '$2,500 + $550 on-time bonus, paid 50% upfront ($1,250), 50% on delivery ($1,250 + on-time bonus).';
$pattern = '$n,nnn';

$result = pattern_match($subject, $pattern, 0);
var_dump($result);

$result = pattern_match($subject, $pattern, 1);
var_dump($result);
function pattern_match($subject, $pattern, $result_as_array) {

    $pattern_len = strlen($pattern);
    if ($pattern_len==0) return false; // error: empty pattern

    // translate $subject with the symboles of the rule ('n', 'c' or 'C')
    $translate = '';
    $subject_len = strlen($subject);
    for ($i=0 ; $i<$subject_len ; $i++) {
        $x = $subject[$i];
        $ord = ord($x);
        if ( ($ord>=48) && ($ord<=57) ) { // between 0 and 9
            $translate .= 'n';
        } elseif ( ($ord>=65) && ($ord<=90) ) { // between A and Z
            $translate .= 'C';
        } elseif ( ($ord>=97) && ($ord<=122) ) { // between a and z
            $translate .= 'c';
        } else {
            $translate .= $x; // othre characters are not translated
        }
    }

    // now search all positions in the translated string

    // single result mode
    if (!$result_as_array) {
        $p = strpos($translate, $pattern);
        if ($p===false) {
            return false;
        } else {
            return substr($subject, $p, $pattern_len);
        }
    }

    // array result mode
    $result = array();
    $p = 0;
    $n = 0;
    while ( ($p<$subject_len)  && (($p=strpos($translate,$pattern,$p))!==false) ) {
        $result[] = substr($subject, $p, $pattern_len);
        $p = $p + $pattern_len;
    }
    return $result;

}