在PHP中解析包含点的字符串

时间:2014-03-20 16:42:21

标签: php parsing

我会解析以下字符串:

$str = 'ProceduresCustomer.tipi_id=10&ProceduresCustomer.id=1';                 
parse_str($str,$f);

我希望将$ f解析为:

array(
    'ProceduresCustomer.tipi_id' => '10',
    'ProceduresCustomer.id' => '1'
)

实际上,parse_str会返回

array(
        'ProceduresCustomer_tipi_id' => '10',
        'ProceduresCustomer_id' => '1'
    )

除了编写我自己的函数之外,还有人知道是否有php函数吗?

3 个答案:

答案 0 :(得分:8)

来自PHP Manual

  

变量名中的点和空格将转换为下划线。例如,<input name="a.b" />变为$_REQUEST["a_b"]

所以,这是不可能的。 parse_str()会将所有期间转换为下划线。如果您确实无法避免在查询变量名中使用句点,则必须编写自定义函数来实现此目的。

以下函数(取自this answer)将查询字符串中每个键值对的名称转换为相应的十六进制形式,然后对其执行parse_str()。然后,他们又恢复原状。这样,不会触及期间:

function parse_qs($data)
{
    $data = preg_replace_callback('/(?:^|(?<=&))[^=[]+/', function($match) {
        return bin2hex(urldecode($match[0]));
    }, $data);

    parse_str($data, $values);

    return array_combine(array_map('hex2bin', array_keys($values)), $values);
}

使用示例:

$data = parse_qs($_SERVER['QUERY_STRING']);

答案 1 :(得分:2)

快点'肮脏。

$str = "ProceduresCustomer.tipi_id=10&ProceduresCustomer.id=1";    

function my_func($str){
    $expl = explode("&", $str);
    foreach($expl as $r){
        $tmp = explode("=", $r);
        $out[$tmp[0]] = $tmp[1];
    }
    return $out;
}

var_dump(my_func($str));

array(2) {
    ["ProceduresCustomer.tipi_id"]=> string(2) "10"
    ["ProceduresCustomer.id"]=>string(1) "1"
}

答案 2 :(得分:0)

这个快速生成的函数尝试正确解析查询字符串并返回一个数组。

第二个(可选)参数$break_dots告诉解析器在遇到点时创建一个子数组(这超出了问题范围,但无论如何我都包含它)。

/**
 * parse_name -- Parses a string and returns an array of the key path
 * if the string is malformed, only return the original string as a key
 *
 * $str The string to parse
 * $break_dot Whether or not to break on dots (default: false)
 *
 * Examples :
 *   + parse_name("var[hello][world]") = array("var", "hello", "world")
 *   + parse_name("var[hello[world]]") = array("var[hello[world]]") // Malformed
 *   + parse_name("var.hello.world", true) = array("var", "hello", "world")
 *   + parse_name("var.hello.world") = array("var.hello.world")
 *   + parse_name("var[hello][world") = array("var[hello][world") // Malformed
 */
function parse_name ($str, $break_dot = false) {
    // Output array
    $out = array();
    // Name buffer
    $buf = '';
    // Array counter
    $acount = 0;
    // Whether or not was a closing bracket, in order to avoid empty indexes
    $lastbroke = false;

    // Loop on chars
    foreach (str_split($str) as $c) {
        switch ($c) {
            // Encountering '[' flushes the buffer to $out and increments the
            // array counter
            case '[':
                if ($acount == 0) {
                    if (!$lastbroke) $out[] = $buf;
                    $buf = "";
                    $acount++;
                    $lastbroke = false;
                // In this case, the name is malformed. Return it as-is
                } else return array($str);
                break;

            // Encountering ']' flushes rge buffer to $out and decrements the
            // array counter
            case ']':
                if ($acount == 1) {
                    if (!$lastbroke) $out[] = $buf;
                    $buf = '';
                    $acount--;
                    $lastbroke = true;
                // In this case, the name is malformed. Return it as-is
                } else return array($str);
                break;

            // If $break_dot is set to true, flush the buffer to $out.
            // Otherwise, treat it as a normal char.
            case '.':
                if ($break_dot) {
                    if (!$lastbroke) $out[] = $buf;
                    $buf = '';
                    $lastbroke = false;
                    break;
                }

            // Add every other char to the buffer
            default:
                $buf .= $c;
                $lastbroke = false;
        }
    }

    // If the counter isn't back to 0 then the string is malformed. Return it as-is
    if ($acount > 0) return array($str);

    // Otherwise, flush the buffer to $out and return it.
    if (!$lastbroke) $out[] = $buf;
    return $out;
}

/**
 * decode_qstr -- Take a query string and decode it to an array
 *
 * $str The query string
 * $break_dot Whether or not to break field names on dots (default: false)
 */
function decode_qstr ($str, $break_dots = false) {
    $out = array();

    // '&' is the field separator 
    $a = explode('&', $str);

    // For each field=value pair:
    foreach ($a as $param) {
        // Break on the first equal sign.
        $param = explode('=', $param, 2);

        // Parse the field name
        $key = parse_name($param[0], $break_dots);

        // This piece of code creates the array structure according to th
        // decomposition given by parse_name()
        $array = &$out; // Reference to the last object. Starts to $out
        $append = false; // If an empty key is given, treat it like $array[] = 'value'

        foreach ($key as $k) {
            // If the current ref isn't an array, make it one
            if (!is_array($array)) $array = array();
            // If the current key is empty, break the loop and append to current ref
            if (empty($k)) {
                $append = true;
                break;
            }
            // If the key isn't set, set it :)
            if (!isset($array[$k])) $array[$k] = NULL;

            // In order to walk down the array, we need to first save the ref in
            // $array to $tmp
            $tmp = &$array;
            // Deletes the ref from $array
            unset($array);
            // Create a new ref to the next item
            $array =& $tmp[$k];
            // Delete the save
            unset($tmp);
        }

        // If instructed to append, do that
        if ($append) $array[] = $param[1];
        // Otherwise, just set the value
        else $array = $param[1];

        // Destroy the ref for good
        unset($array);
    }

    // Return the result
    return $out;
}

我试图正确处理多级密钥。代码有点hacky,但它应该工作。我试图评论代码,如果你有任何问题请评论。

测试用例:

var_dump(decode_qstr("ProceduresCustomer.tipi_id=10&ProceduresCustomer.id=1"));
// array(2) {
//   ["ProceduresCustomer.tipi_id"]=>
//   string(2) "10"
//   ["ProceduresCustomer.id"]=>
//   string(1) "1"
// }


var_dump(decode_qstr("ProceduresCustomer.tipi_id=10&ProceduresCustomer.id=1", true));
// array(1) {
//   ["ProceduresCustomer"]=>
//   array(2) {
//     ["tipi_id"]=>
//     string(2) "10"
//     ["id"]=>
//     string(1) "1"
//   }
// }