如何在PHP中将字符串转换为数组?

3

我有这个字符串:

0=&task=rose&duration=1.25&user=15&1=&task=daisy&duration=0.75&user=25&2=&task=orchid&duration=1.15&user=7

我想要这样的数组结构:

array(
    array( "task" => "rose", 
           "duration" => 1.25,
           "user" => 15 
         ),
    array( "task" => "daisy", 
           "duration" => 0.75,
           "user" => 25,
         ),
    array( "task" => "orchid", 
           "duration" => 1.15,
           "user" => 7 
         )
      )

1
这是一个URL的查询字符串吗?如果是,检查$_GET关联数组。 - Matt Ellen
我认为这应该能回答你的问题:http://stackoverflow.com/questions/3533100/how-to-convert-string-to-array - Matt Ellen
6个回答

2
现在,parse_url对于你的情况不起作用,因为它会覆盖重复的条目。你必须手动提取和分组。
$str = 'decoded_name=0=&task=rose&duration=1.25&user=15&1=&task=daisy&duration=0.75&user=25&2=&task=orchid&duration=1.15&user=7';
preg_match_all('#(\w+)=([^&=]*)(?:&|$)#', $str, $matches, PREG_SET_ORDER); 

$result = array();
$i = 0;    
foreach ($matches as $m) {
    list(, $key, $value) = $m;

    if (!strlen($value)) { 
       $i = (int)$key;
    }
    else {
       $result[$i][$key] = $value;
    }
}

这个技巧是要注意没有值的数字键,它们会将你的组分开。循环将生成以下嵌套数组:
[0] => Array
    (
        [task] => rose
        [duration] => 1.25
        [user] => 15
    )

[1] => Array
    (
        [task] => daisy
        [duration] => 0.75
        [user] => 25
    )

[2] => Array
    (
        [task] => orchid
        [duration] => 1.15
        [user] => 7
    )

@00001:很酷。感谢反馈!请不要忘记用✔勾选标记我的、Jon的或ReturnTrue的答案。 - mario
任何真正专业的PHP工程师都会告诉你,有太多经验不足的开发人员以极低劣的方式重新实现轮子。这里真正的教训是教00001关于parse_str(),并让他微调输出格式(我们必须假设这是在他的直接操作下完成的)。创建更复杂的黑客解决已经解决的问题只会扩散旧的反模式。 - Theodore R. Smith
@Theodore R. Smith。你的假设是错误的(这与专业相反)。改变问题域或任务以适应愚蠢的解决方案并不能完全解决问题。OP有两个这样的答案可供选择,但没有选择。你的hackish解决方案和你关于反模式的无根据的抨击并不能解决实际提出的问题。 - mario
@mario - 假设你正在运行一个有三个公司消费者的网络服务。第四个客户来了,说:“我们不想遵守你精心编写的XML API。我们的方法是这样的...”。你会自动选择a)建议客户尝试使用你的API,可能通过适配器模式,b)更改你现有的API并重新制定其他客户端的工作流程吗?你说你会选择B)。那是不合逻辑的。 - Theodore R. Smith
@Theodore:这是一个真实的观点。然而,我会尽可能地使API易于使用,以适应其他语言。(URL参数中的数组语法在PHP中有点独特,在其他地方并不是很重要)。作为最后的手段,可以使用一个小的$_GET重写包装器(甚至通过.htaccess)来解决问题。--请注意,OP的情况与URL无关。正如他后来的问题所揭示的那样,他读取了一个非常混乱的文件交换格式。 - mario

1

我很乐意帮助!

<?php

$input = 'data[0][task]=rose&data[0][duration]=1.25&data[0][user]=15&' .
         'data[1][task]=daisy&data[1][duration]=0.75&data[1][user]=25&' .
         'data[2][task]=orchid&data[2][duration]=1.15&data[2][user]=7';

$output = array();

parse_str($input, $output);

print_r($output);

hopeseekr@7250MHz ~ $ php stack_5350749.php
Array
(
    [data] => Array
        (
            [0] => Array
                (
                    [task] => rose
                    [duration] => 1.25
                    [user] => 15
                )

            [1] => Array
                (
                    [task] => daisy
                    [duration] => 0.75
                    [user] => 25
                )

            [2] => Array
                (
                    [task] => orchid
                    [duration] => 1.15
                    [user] => 7
                )

        )

)

由于重新解析您的错误输入字符串比回答您的核心问题要困难得多,如果您还需要帮助,请考虑为此打开一个新问题。


2
-1:楼主要求完全不同。在点赞之前请仔细阅读,大家。 - Jon
实际上,我使用'='和'&'将二维数组的输出作为字符串获取......所以我得到了这样的输出......我想再次将该字符串转换回原始数组..... - 00001
parse_str()比任何while循环都更具可扩展性。在任何具有较小流量的站点上,只需尝试使用任何大量数据即可。 - Theodore R. Smith
2
-1 为了编造微观优化的借口,给其他人投反对票,并从另一个参与者那里抄袭答案而不加注明。 - mario
@mario 给你点赞,因为你很有礼貌地表达了自己的观点。我希望更多人像你一样诚实和勇敢,真的。 - Theodore R. Smith

1

你无法通过使用作为 $_GET['user'] 发送的标头来实现你想要的目标,因为它会被覆盖为 7(之前的将被覆盖)。如果你想要走这条路,你需要一个查询字符串...

decoded_name=0=&task[]=rose&duration[]=1.25&user[]=15&1=&task[]=daisy&duration[]=0.75&user[]=25&2=&task[]=orchid&duration[]=1.15&user[]=7

如果您将其作为查询字符串,那么只需使用array_push即可。否则,您将不得不手动解析字符串 - 再次使用array_push生成子数组,然后将其推入父级中。

0
这是一个没有正则表达式的解决方案。我对它感到更舒适。
$str = 'decoded_name=0=&task=rose&duration=1.25&user=15&1=&task=daisy&duration=0.75&user=25&2=&task=orchid&duration=1.15&user=7';

// Get rid of "decoded_name", which we don't need
$str = str_replace('decoded_name=', '', $str);

$arr = explode('&', $str);
array_push($arr, '0='); // Add sentinel value to simplify the loop
$results = array();
$parsing = array();

foreach ($arr as $item) {
    // If a new task begins
    if (strspn($item, '0123456789') == strlen($item) - 1) {
        // Add the current item if there is one
        if (!empty($parsing)) {
            $results[] = $parsing;
        }

        // Prepare to parse another item
        $parsing = array();
        continue;
    }

    // Add data to the current item    
    list($key, $value) = explode('=', $item);
    $parsing[$key] = $value;
}

在此处查看它的运行情况


PHP中的字符串函数在循环中几乎总是比正则表达式慢。:/ -- strspn这一行看起来非常有趣。你能解释一下它是做什么的/如何工作的吗?(从未见过这样的结构。) - mario
@mario:我没有测量过,但是我预计相反的表现。这里的 strspn(http://www.php.net/manual/en/function.strspn.php)条件检查 $item 中除最后一个字符外的所有字符是否都是数字。这与 0=, 1= 等匹配,并表示我们遇到了新的结果项。 - Jon
@Jon:想打赌吗 :} 20美分?(我经常测量,我可以保证PCRE在这里表现更好。虽然这不应该是决定性因素)。--无论如何,感谢您的解释。并且+1,因为您的解决方案看起来也是正确的。 - mario
1
@mario:到底是怎么回事 :) 我的基准测试在这里:http://ideone.com/b88tG(每种方法进行3次x 100K迭代)。 在我的机器上的结果(以秒为单位):无正则表达式:2.251982 2.24632 2.245951 有正则表达式:2.670076 2.674494 2.667474。你欠我20美分 ;) - Jon
@Jon。哇,酷炫的测试脚本。我得单独给你20美分。但是,ideone很大程度上扭曲了结果。这些在线测试工具运行在旧版PHP和libPCRE版本以及某种沙盒中。我有当前的pcre 8.12和php 5.3 amd64,我的结果是11.082897与6.763827正则表达式;P - 但我现在要在真实服务器上进行测试... - mario
显示剩余4条评论

0
$str = "decoded_name=0=&task=rose&duration=1.25&user=15&1=&task=daisy&duration=0.75&user=25&2=&task=orchid&duration=1.15&user=7";

$str = preg_replace("/&\d=/", "", $str);
$str = preg_replace("/&/", "=", $str);
$tmp = preg_split("/=+/", $str);

$length = count($tmp);

for ($i = 2, $j = 0; $i < $length; $i+=6, $j++) {
    $arr[$j] = array($tmp[$i] => $tmp[$i + 1], $tmp[$i + 2] => $tmp[$i + 3], $tmp[$i + 4] => $tmp[$i + 5]);
}

print_r($arr);

0
尝试编辑您表单中的输入/文本区域,将 name="task" 更改为 name="data[task]",然后您将在 var_dump($_GET) 中看到您的数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接