【问题标题】:PHP preg_match_all expressionPHP preg_match_all 表达式
【发布时间】:2011-01-11 10:18:24
【问题描述】:

我几乎没有 regx 的经验,但尽我所能。

我有一个这样的字符串:

$fString = "Name=Sök,Value=2,Title=Combine me,Options=[Item1=1,Item2=2,Item3=3]";

我想得到一个如下所示的数组:

Array[0] = "Name=Sök"
Array[1] = "Value=2"
Array[2] = "Title=Combine me"
Array[3] = "Options=[Item1=1,Item2=2,Item3=3]"

到目前为止,我所做的是:

preg_match_all("/[^,]*[\w\d]*=[^,]*/",$fString,$Data);

但我不知道如何修复最后一个“选项”。

Array ( [0] => Array ( [0] => Name=S�k [1] => Value=2 [2] => Title=Combine me [3] => Options=[Item1=1 [4] => Item2=2 [5] => Item3=3] ) )

...为什么结果是数组中的数组?!?


[编辑]

我想我需要解释一下我在这里尝试做什么的整个想法,我不确定我是否已经走上了正确的道路。

我创建了一些类,我将所有“持久”变量存储在一个数组中。我有一个函数可以序列化这个数组,这样我就可以存储在数据库中。

我对 serialize() 函数了如指掌,但我正在做一些过滤,所以我不能按原样使用它,而且我也更喜欢让它更具可读性以进行手动编辑。这个数组可以有嵌套数组,需要保留。当我从数据库中全部读取回来时,必须重新创建原始数组。

我使用 eval() 命令完成了所有操作,但在嵌套数组时遇到了麻烦,因为 " 或 ' 字符破坏了主要的外部字符串。所以这种方法是尝试在没有嵌套字符串的情况下序列化所有内容需要保存。

所以如果我可以用 preg_match_all 解决嵌套数据,我就在那里,否则我需要想出另一个解决方案。

我猜数据也需要转义,比如 , 和 [ ]

【问题讨论】:

  • 结果总是在一个数组中。 $Data 始终输出具有多种结果类型的多维数组。
  • 值中可以有逗号吗,比如"Title=Combine,me"?如果是,该案如何处理?
  • 你需要一个迷你解析器。看看@SirDarius 做了什么。您只需要注意最近的,[,然后前往[ 或返回] 收集的列表。
  • 阅读您的编辑后,我可以说这个用例需要通过 json_encode 函数进行 JSON 序列化。 JSON 是人工可编辑的,并且允许数组嵌套。另外,使用 json_decode 解码为 php 变量非常容易。

标签: php regex arrays preg-match-all


【解决方案1】:

这是一个基本上可以满足您需要的功能:

function explode_me($str) {
    $a = array();
    $v = "";
    $ignore = false;
    for ($i = 0; $i < strlen($str); $i++) {
        if ($str[$i] == ',' && !$ignore) {
            $a[] = $v;
            $v = "";
        }
        else if ($str[$i] == '[' && !$ignore) {
            $ignore = true;
            $v .= $str[$i];
        }
        else if ($str[$i] == ']' && $ignore) {
            $ignore = false;
            $v .= $str[$i];
        }
        else {
            $v .= $str[$i];
        }
    }
    $a[] = $v;
    return $a;
}

测试它:

$str = "Name=Sök,Value=2,Title=Combine me,Options=[Item1=1,Item2=2,Item3=3]";
$a = explode_me($str);

print_r($a);

哪个打印:

Array
(
    [0] => Name=Sök
    [1] => Value=2
    [2] => Title=Combine me
    [3] => Options=[Item1=1,Item2=2,Item3=3]
)

【讨论】:

  • 我使用了你的 JSON 建议,到目前为止似乎很有魅力:D
【解决方案2】:
(\w+)=(\[[^\]]+\]|[^,]+)

这分解为:

(\w+)        # a word (store in match group 1)
=            # the "=" character
(            # begin match group 2
  \[         #   a "[" character
  [^\]]+     #   anything but "]" character
  \]         #   a "]" character
  |          #   or...
  [^,]+      #   anything but a comma
)            # end match group 1

通过preg_match_all()申请:

$fString = "Name=Sök,Value=2,Title=Combine me,Options=[Item1=1,Item2=2,Item3=3]";

$matches = array();
preg_match_all("/(\\w+)=(\\[[^\\]]+\\]|[^,]+)/", $fString, $matches);

这会产生比您想要的更详细的内容:

Array
(
    [0] => Array
        (
            [0] => Name=Sök
            [1] => Value=2
            [2] => Title=Combine me
            [3] => Options=[Item1=1,Item2=2,Item3=3]
        )

    [1] => Array
        (
            [0] => Name
            [1] => Value
            [2] => Title
            [3] => Options
        )

    [2] => Array
        (
            [0] => Sök
            [1] => 2
            [2] => Combine me
            [3] => [Item1=1,Item2=2,Item3=3]
        )

)

$result[0] 是你想要的。 $result[1]$result[2] 分别是属性名称和值,这使您可以立即使用它们,而不是进行额外的步骤,将 "Options=[Item1=1,Item2=2,Item3=3]" 之类的内容拆分为正确的 =

【讨论】:

  • @Max:那会是什么? :)
  • 嗯,为什么答案是带有数组的数组,非常好用:D
【解决方案3】:

如果您可以更改项目之间的分隔符(将 Item1=1,Item2=2,Item3=3 更改为 Item1=1|Item2=2|Item3=3),您可以轻松地使用 explode(',',$fString) 来将字符串转换为数组。

我也可以提供这段代码来改变分隔符,因为我没有使用正则表达式的经验:

$newstr = str_replace(',Item','|Item',$fString);
$newarray = explode(',',$newstr);

$newarray 将如下所示:

Array[0] = "Name=Sök"
Array[1] = "Value=2"
Array[2] = "Title=Combine me"
Array[3] = "Options=[Item1=1|Item2=2|Item3=3]"

【讨论】:

  • 我之前也考虑过这一点,但我需要能够再次迭代 [...] 块以解开它们。
【解决方案4】:

这是一个更适合解析而不是正则表达式提取的问题。您可以将特殊情况分开以使其工作:

preg_match_all("/(\w+)=( \w[^,]+ | \[[^\]]+\] )/x", $str, $m);
$things = array_combine($m[1], $m[2]);

会给你一个 PHP 变量,比如(但你可以访问 $m[0] 来获取未解析的字符串):

[Name] => Sök
[Title] => Combine me
[Options] => [Item1=1,Item2=2,Item3=3]

您也可以在Options 上重新应用该功能来爆炸。

这个诀窍还是要区分\w 以字母开头的任何内容和\[...\] 封闭的选项。在那里你必须让它匹配^]所有非右括号,就是这样。

【讨论】:

  • 谢谢,这实际上是我想要的结果。只有一个问题:当我迭代 [...] 参数(首先删除 [...])“Item1=1,Item2=2,Item3=3” 它失败了,因为没有数字匹配。我试图放入 \d 但无法使其工作。此外,我需要能够嵌套 [...] 块,例如 Controls=[Options=[Item1=1,Item2=2],Name=Foo] 也许这不是正确的方法?!?
  • @MaxKielland:你不需要\d。上面的失败是+,把它改成\w[^,]*。但是对于嵌套列表,恐怕正则表达式变得难以管理。不过,您可以尝试在其中嵌套另一个 \\[...\\]
【解决方案5】:

所以,这是另一种方法。它是用于嵌套结构的迷你解析器。如果您需要转义码,请调整正则表达式。

function parse(&$s) {
    while (strlen($s) && preg_match("/^(.*?)([=,\[\]])/", $s, $m)) {
        $s = substr($s, 1 + strlen($m[1]));
        switch ($m[2]) {
            case "=":
               $key = $m[1];
               break;
            case ",":
               if (!isset($r[$key])) {
                  $r[$key] = $m[1];
               }
               break;
            case "[":
               $r[$key] = parse($s);
               break;
            case "]":
               return $r;
        }
    }
    if ($s) { $r[$key] = $s; } // remainder
    return $r;
}

【讨论】:

  • 我会看看这个并与 SirDarius 提出的 JSON 进行比较。我还阅读了一些关于 Serializable Interface 的内容,看起来我可以朝这个方向做点什么……
  • @MaxKielland:它实际上是基于我编写的 JSON 解析器。而且我已经用嵌套列表对其进行了测试。对于这种情况,我已经把它压缩得太多了,所以你需要打印语句来调试正在发生的事情。但是尝试一下您的一个复杂示例。
  • 我会回来的,当我实现并测试了这个。目前我正在测试要序列化的组件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-12
  • 2014-02-24
相关资源
最近更新 更多