【问题标题】:PHP - search file lines from pattern to another pattern and put them into arrayPHP - 从模式搜索文件行到另一个模式并将它们放入数组
【发布时间】:2018-04-12 11:06:13
【问题描述】:

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

...
;
; 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."
    )
);

在这种情况下,cmets 是“;”所以它根本不需要解析。注释掉的部分是修复的,比如“基本配置”和“邮件配置”,“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
    }
}
?>

如果你能帮我处理一个块(base、mail 或 www),它会对我有很大帮助,基于此,我可以解决其他块。

【问题讨论】:

  • 贴出你试过的代码
  • 编辑了我的问题并尝试了。我认为这不会有太大帮助。

标签: php


【解决方案1】:

另一种解决方案

<?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);

【讨论】:

  • 看起来很好,但它不起作用。它给出了一个空数组作为结果。我认为 preg_match 不起作用,因为它没有进入第一个 if 子句。
  • 你好@ankabout,你是对的。这是我的错,因为我尽可能短地复制了我的示例,因此我写了“基本配置”,但在我的原始示例中它是“区域 example.com 的基本配置”因此您的正则表达式不匹配。 :) 但是您的答案既简单又好,所以我会接受它作为最佳答案。您能否帮我处理正则表达式并将其修改为 [a-z]+ config
  • @Darwick 当然,您只需要删除末尾的 $,(它说字符串必须在 'config' 结束)因为您不希望删除 @987654324 @.
【解决方案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.
        )

)

【讨论】:

  • 几乎很好,但是文件应该以另一个记录开头并注释掉在我测试时将失败此处理的部分。您是否应该修改它以从“基本配置”开始 cehck?我自己尝试过修改它,但我不知道如何。
  • @Darwick 我已经编辑了我的答案,以便为未来的读者回滚到第一个版本,以匹配您问题的预期输出。您评论后的第二个版本是here
【解决方案3】:

注意事项:

我已更新此答案只是为了使其功能齐全。现在它处理所有配置选项。

此示例使用“基于表”的方法并逐行读取文件。换行符 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);
?>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-25
    • 1970-01-01
    • 2019-07-18
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    • 2011-08-08
    相关资源
    最近更新 更多