2014-03-03 90 views
2

我需要将文本文件解析为php数组。这是我的文本文件:将格式化文本文件解析为PHP数组

file: slide1.jpg | title: Title here      | description: Aenean eleifend ultrices leo at venenatis. Suspendisse luctus | crop: top 
file: slide2.jpg | description: Phasellus ac tortor ut dolor blandit tincidunt | title: Nullam cursus         | crop: bottom 
file: slide3.jpg | title: Hendrerit lacinia nisl   | description: Tortor ut dolor blandit tincidunt        | crop: bottom 
file: slide4.jpg | title: Morbi hendrerit lacinia nisl | description: Maecenas venenatis lectus vitae         | crop: left 

我想将它解析为这样的结构数组:

array(4) { 
    "slide1.jpg" => array (
    "title" => "Title here", 
    "description" => "Aenean eleifend ultrices leo at venenatis. Suspendisse luctus", 
    "crop" => "top" 
), 
    "slide2.jpg" => array (
    "title" => "Nullam cursus", 
    "description" => "Phasellus ac tortor ut dolor blandit tincidunt", 
    "crop" => "top" 
), 
    "slide3.jpg" => array (
    "title" => "Hendrerit lacinia nisl", 
    "description" => "Tortor ut dolor blandit tincidunt", 
    "crop" => "top" 
), 
    "slide4.jpg" => array (
    "title" => "Morbi hendrerit lacinia nisl", 
    "description" => "Maecenas venenatis lectus vitae", 
    "crop" => "top" 
) 
} 

我有许多重复的foreach语句尝试,但它不是那么有效,代码变得非常冗长。有没有人知道一种更简单的方法。

+1

在文本文件中的内容没有被格式化为CSV和“列”不用排队。这些文本文件是否以某种方式生成? –

+3

这不是一个CSV文件。至少,这可能是'| SV'。 –

+1

csv文件可以用任何东西分隔,它不一定是逗号。我使用|作为分隔符,因为逗号是常见的文本字符。它被手动编辑/维护以便于结构。新行定义了一个新项目,管道将属性分开。 – Cruising2hell

回答

4

首先:小心!

这是潜在的毛病,有很多可能的例外。我公司提供的解决方案确实:

  • ...不使用正则表达式,这应该使代码更易读,易维护,亚达内容十分重要:)
  • ...不检查某个值包含管道|,这会绊倒这件事。另一方面,值可以安全地包含冒号。
  • ...不处理多字节字符。
  • ...不在乎表现。
  • ...假设钥匙"file"始终存在。
  • ...不插入丢失的密钥,这应该在其他地方处理。

在盲目复制/粘贴之前考虑这些注意事项! ;)

此外,我的解决方案包含每个元素中的文件名,这是多余的。但是消除它会使解决方案变得更加混乱而没有太多的价值。

这里有一个解决方案:

<?php 

/** 
* Parse a line of the file. Returns an associative array, using the part 
* before the colon as key, the following part as value. 
* 
* @param $line A line of text. 
*/ 
function parse_line($line) { 
    // split on each '|' character. 
    $fields = explode('|', $line); 
    $data = array(); 
    foreach($fields as $field) { 
    // unpack key/value from each 'key: value' text. This will only split on 
    // the first ":", so the value may contain colons. 
    list($key, $value) = explode(':', $field, 2); 
    // remove surrounding white-space. 
    $key = trim($key); 
    $value = trim($value); 
    $data[$key] = $value; 
    } 
    return $data; 
} 


/** 
* Parses a file in the specified format. 
* 
* Returns an associative array, where the key is a filename, and the value is 
* an associative array of metadata. 
* 
* @param $fname The filename 
*/ 
function parse_file($fname) { 
    $handle = fopen($fname, "r"); 
    $lines = array(); 
    if ($handle) { 
    while (($line = fgets($handle)) !== false) { 
     $data = parse_line($line); 
     $lines[$data["file"]] = $data; 
    } 
    } else { 
    // error opening the file. 
    } 
    return $lines; 
} 

var_dump(parse_file("testdata.txt")); 
+0

非常感谢。这与我所需要的最接近。 – Cruising2hell

+0

我只能强调@MarcB的注释。 *如果*您可以控制生成该文件的进程,*使用*可解析的格式,如JSON或XML。这些格式处理您可能遇到的所有奇怪的角落案例。特别是当文件包含意外输入时! – exhuma

-1

尝试:

$new_array = array(); 
while (($data = fgetcsv($csvfile, 1000, ";")) !== FALSE) { 
    $new_array[$data[0]] = array('title' => $data[1], 'description' => $data[2], 'crop' => $data[3]); 
} 

var_dump($new_array); 
+0

谢谢,但这似乎将进入永久循环。 – Cruising2hell

1

下应该做的伎俩。

$rows = array(); 

foreach (preg_split('#\n#', file_get_contents('blah.txt')) as $line) { 
    if (preg_match_all('#([^"|]+)\s*:\s*([^|]+)#', $line, $parts)) { 
    $properties = array_map('trim', $parts[1]); 
    $values = array_map('trim', $parts[2]); 

    assert(count($properties) == count($values)); 

    $row = array(); 
    foreach ($properties as $index => $propertyName) { 
     $row[$propertyName] = $values[$index]; 
    } 
    $rows[] = $row; 
    } 
} 

var_dump($rows); 
+0

有趣,它没有运行。你可以定义$零件吗?我认为它可能会遇到错误。 – Cruising2hell

+0

零件不需要定义,因为它在运行时会被填充。如果需要,你可以在if部分之前创建它= array() –