PHP - 从模式到另一个模式搜索文件行并将它们放入数组中

时间:2018-04-12 11:06:14

标签: php

我有一个文本文件(实际上是一个区域文件),如下所示:

...
;
; base config
; -----------------------------------------------------------------
@       14400   IN      A       1.2.3.4
@       14400   IN      AAAA    1:2:3::4
;
; mail config
; -----------------------------------------------------------------
mail    14400   IN      A       1.2.3.4
mail    14400   IN      AAAA    1:2:3::4
@       14400   IN      MX 10   mail.example.com.
;
; www config
; -----------------------------------------------------------------
www     14400   IN      CNAME   example.com.
...

我想将每个没有注释掉的行解析为数组,逐块。所以看起来应该是这样的:

$array = array(
    "base" => array(
        "0" => "@       14400   IN      A       1.2.3.4",
        "1" => "@       14400   IN      AAAA    1:2:3::4"
    ),
    "mail" => array (
        "0" => "mail    14400   IN      A       1.2.3.4",
        "1" => "mail    14400   IN      AAAA    1:2:3::4",
        "1" => "@       14400   IN      MX 10   mail.example.com."
    ),
    "www" => array(
        "0" => "www     14400   IN      CNAME   example.com."
    )
);

在这种情况下,评论是“;”所以它根本不需要解析。注释掉的部分是修复的,比如“基本配置”和“邮件配置”,而“www配置”没有改变,它每次都像我的例子一样。但是每个块中的记录(未通过;省略)可能会发生变化,因此可能只有1条记录,或5,10或任何记录。我试着把文本文件放到一个数组中,用foreach循环处理它,然后用preg_match()搜索相应的行但是它没有解决,因为我不知道有多少记录(行)到来文件的下一部分。她是我的尝试:

<?php
// Get lines
$lines = file('file.txt');

// Loop through our array
foreach ($lines as $line_num => $line) {
    if (preg_match("/\bbase config\b/i", $line)) {
        $line++
        // I don't know how to continue and find the next section
    }
}
?>

如果你可以帮助我处理一个区块(基地,邮件或www),它会对我有所帮助,基于此,我可以解决其他问题。

3 个答案:

答案 0 :(得分:2)

使用foreach(),您可以检查第一行是否以;开头,并检查该行的内容是否为配置名称。您可以使用trim()list()来检查该行的内容:

$lines = file('file.txt');

$config = '';
$array = []; // outputs array:
foreach ($lines as $line) { 
    if (strpos($line, ';') === 0) { // if starts with ';'
        $line = trim($line, '-; '); // remove unwanted characters
        if (!$line) continue; // if empty, it's an unwanted line
        list($config) = explode(' ', $line, 2); // get the config name
        continue;
    }
    $array[$config][] = $line; // store line in config array
}
print_r($array);

输出:

Array
(
    [base] => Array
        (
            [0] => @       14400   IN      A       1.2.3.4
            [1] => @       14400   IN      AAAA    1:2:3::4
        )
    [mail] => Array
        (
            [0] => mail    14400   IN      A       1.2.3.4
            [1] => mail    14400   IN      AAAA    1:2:3::4
            [2] => @       14400   IN      MX 10   mail.example.com.
        )
    [www] => Array
        (
            [0] => www     14400   IN      CNAME   example.com.
        )

)

答案 1 :(得分:2)

另一种解决方案

<?php
$filepath = __DIR__ . '/file.txt';

$validSection = false;
$startingSectionPattern = '/^; [a-z]+ config$/i';
$startingSections = ['base' => '; base config', 'mail' => '; mail config', 'www' => '; www config'];
$res = [];

foreach (file($filepath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
    if ($line[0] == ';' && preg_match($startingSectionPattern, $line)) {
        $validSection = false;
        $key = array_search($line, $startingSections);
        if ($key !== false) {
            $validSection = true;
        }
    }

    if ($validSection && $line[0] != ';') {
        $res[$key][] = $line;
    }
}

var_dump($res);

答案 2 :(得分:1)

备注:

我已经更新了这个答案,只是为了让它完全正常运行。现在它处理所有配置选项。

此示例使用“基于表格”的方法并逐行读取文件。换行符char(chars)包含在$ output中。

zones.txt

;
; base config
; -----------------------------------------------------------------
@       14400   IN      A       1.2.3.4
@       14400   IN      AAAA    1:2:3::4
;
; mail config
; -----------------------------------------------------------------
mail    14400   IN      A       1.2.3.4
mail    14400   IN      AAAA    1:2:3::4
@       14400   IN      MX 10   mail.example.com.
;
; www config
; -----------------------------------------------------------------
www     14400   IN      CNAME   example.com.
;

zones.php

<?php
$output = array();
$configName = '';
$configFound = false;

$handle = fopen("zones.txt", "r");
if ($handle) {
    while (!feof($handle)) {
        $row = fgets($handle);
        if (substr($row, 0, 1) == ';') {
            if (strpos($row, "config") === false) {
                $configFound = false;
            } else {
                $configFound = true;
                $configName = $row;
                $configName = str_replace(' ', '', $configName);
                $configName = str_replace(';', '', $configName);
                $configName = str_replace('config', '', $configName);
            }   
        } else {
            $output[$configName][] = $row;
        }
    }
    fclose($handle);
}

var_dump($output);
?>