使用 BEGIN 和 END 解析具有无限数量的嵌套数组的数据文件


Parsing a data file with an unlimited number of nested arrays using BEGIN and END

如果你

觉得慷慨的话,可以在伪中或在PHP中寻找答案。

目前我有一个具有以下语法的文件:

ITEM 1
Pet Dog
Origin Earth
BEGIN Square
   ITEM 2
   BEGIN "0 0" Type "Earth over" Temp 0.1 END
   BEGIN "0 1" Type "Earth over" Temp 0.1 END
   BEGIN "0 2" Earth 0.1827 END
END
BEGIN "0100"
   ITEM 2
   Origin Earth
   BEGIN Alpha
      ID 1
      Name Alpha
   END
   BEGIN "Need"
      BEGIN "00" id.a END
      BEGIN "01" id.b END
   END
END

我希望能够获取它并将其解析为类似于以下内容的可用数组:

array(
   "ITEM" => "1",
   "Pet" => "Dog",
   "Origin" => "Earth",
   "Square" => array(
      "ITEM" => "2",
      "0 0" => array(
         "Type" => "Earth over",
         "Temp" => "0.1"
      ),
      "0 1" => array(
         "Type" => "Earth over",
         "Temp" => "0.1"
      ),
      "0 2" => array(
         "Earth" => "0.1827"
      ),
   ),
   "0100" => array(
      "ITEM" => "2",
      "Origin" => "Earth",
      "Alpha" => array(
         "ID" => "1",
         "Name" => "Alpha"
      ),
      "Need" => array(
         "00" => "id.a",
         "01" => "id.b"
      )
   )
)

请注意,我不担心值类型 - 字符串非常适合我正在做的事情。

这是一个解析该文本的函数。如果格式比问题中显示的更复杂,则可能需要进行调整和添加。当输入数据与预期格式不匹配时,它还需要一些错误处理。

/**
 * Parse the provided lines of text into an array.
 * Warning: it modifies the input parameter. At the end of the execution, $lines will be empty.
 */
function parseData(array &$lines)
{
    $result = array();                                 // this is where the current block is stored
    // Process one line at a time...
    do {
        $l = trim(array_shift($lines));                // extract the first line into $l (and remove it from $lines)
        $p = str_getcsv($l, ' ', '"');                 // split $l into words (take care of strings eclosed in quotes)
        $key = array_shift($p);                        // get the first word from the line
        switch ($key)
        {
        default:                                       // simple "key value" lines
            $result[$key] = implode(' ', $p);          // combine the remaining words from $p into a single string
            break;
        case 'BEGIN':                                  // start a new block
            $key = array_shift($p);                    // the real key in the array follows the 'BEGIN' keyword
            if (end($p) == 'END') {                    // check if the entire block is on a single line
                array_pop($p);                         // remove 'END' from the end of the array
                if (count($p) == 1) {                  // only one word remaining in $p:
                     $result[$key] = array_shift($p);  //              it is the value
                } else {                               // more than one word in $p: this is a list of properties
                     $aa = array();                    // put the values of this one-line block here
                     while (count($p) > 1) {
                         $k = array_shift($p);         // they come in pairs: key followed by value
                         $v = array_shift($p);
                         $aa[$k] = $v;
                     }
                     $result[$key] = $aa;              // the entire line was parsed; store it
                }
            } else {                                   // the last word on the line is not 'END'
                $result[$key] = parseData($lines);     // recursively call this function to parse the inner block and store its result
            }                                          // it will return after it consumes the line that starts with 'END'
            break;
        case 'END':                                    // here ends the block
            return $result;                            // return the collected values
        }
    } while (count($lines));                           // ... until there are no more lines to process
    return $result;                                    // no more lines to process; return the collected data
}

如何使用它:

$text  = file_get_contents('1.txt');
$lines = explode("'n", trim($text));
$data = parseData($lines);
print_r($data);