【问题标题】:PHP - Perform parsing rules on nested arrayPHP - 对嵌套数组执行解析规则
【发布时间】:2019-10-03 11:02:33
【问题描述】:

所以我有一个嵌套数组,它模仿表格布局(列和行):

{
    "1": [
        {
            "row": "My name is Trevor\n"
        },
        {
            "row": "Can you see me?\n"
        },
        {
            "row": "\f"
        }
    ],
    "2": [
        {
            "row": Hey there! Some other text.\n"
        },
        {
            "row": "What is up?\n"
        },
        {
            "row": "\f"
        }
    ],
    "3": [
        {
            "row": "Some text on the third column. First row."
        },
        {
            "row": "\f"
        }
    ]
}

所以“1”、“2”、“3”是列,然后在每列下,可以有任意数量的行。

现在我正在尝试这样做,这样我的用户就可以对任何一个执行各种解析规则:

  1. 所有列和所有行。
  2. 特定列和所有行。

每当一个列/行被解析后,它应该返回到“原始数组”。

为此,我创建了一个类,它将应用我指定的不同解析规则。获取解析规则工作正常。我目前停留在实际的文本转换/解析方面。

假设我有一个名为“regexTextReplace”的解析规则,如下所示:

class regexTextReplace
{
    private $pattern;
    private $replacement;

    public function __construct(array $arguments)
    {
        $this->pattern = $arguments['pattern'];
        $this->replacement = $arguments['replacement'];
    }

    public function apply(array $table, $column = false): array
    {
        $table = $column ? $table[$column] : $table;

        return array_map('self::regex_replace', $table);
    }

    public function regex_replace(array $table)
    {
        return preg_replace($this->pattern, $this->replacement, $table);
    }
}

这就是我的使用方式:

$options = [
    'pattern' => '/Trevor/i',
    'replacement' => 'Oliver',
];
$engine = new regexTextReplace($options);
$columns = $engine->apply($document->content, 1); //"1" is the specific column.

$columns 返回:

[
  {
    "row": "My name is Oliver\n"
  },
  {
    "row": "Can you see my?\n"
  },
  {
    "row": "\f"
  }
]

这里有两个问题:

  1. 它成功应用了解析规则(Trever 被替换为 Oliver)。但它只返回第一列,但我希望对整个原始数组进行转换。
  2. 如果我从 apply() 方法中删除 1,则会出现以下错误:
Array to string conversion

在下面一行:

return preg_replace($this->pattern, $this->replacement, $table);

谁能指导我正确的方向,这样我就可以对任何列或所有列执行我的解析规则,并将转换后的数据返回到我的原始数组?

【问题讨论】:

  • 因为这看起来很复杂:您是否尝试过将 TDD 应用于此?就像开始为最简单的案例编写测试,然后继续下一个更困难的案例?这将帮助你保持这个类的可维护性
  • 在此处查看您的条件:当column 参数为假值时,$table = $column ? $table[$column] : $table; 表将作为数组出现,因此它抱怨Array to string conversion。我宁愿让table的值保持一致,也就是一个数组,然后每次apply()接到一个调用就简单的循环一遍。

标签: php arrays laravel transformation


【解决方案1】:

您可以将您的 apply 方法重写为:

public function apply(array $table, $columns = false): array
{
    $columns = $columns === false ? array_keys($table) : (array)$columns;

    return array_map(function ($column) use ($table, $columns) {
      return in_array($column, $columns) ? array_map('self::regex_replace', $table[$column]) : $table[$column];
    }, array_keys($table));
}

您可以传递单个列、列数组或不传递任何内容 (false) 来指定要调整的列。

演示:https://3v4l.org/Kn4FY

【讨论】:

  • 但是 OP 的整个问题是,即使他只处理一列,他也想返回 整个 数组......
  • @Nick 我才意识到,哈哈。我会编辑我的答案(虽然你的看起来很好)。
  • @oliverbj 编辑了我的帖子以考虑到尼克的评论。
【解决方案2】:

我会重写 apply 函数来循环整个表,如果 column 参数未设置,或者如果它与当前表列匹配,则处理每一列:

public function apply(array $table, $column = false): array
{
    $out = array();
    foreach ($table as $col => $rows) {
        if ($column === false || $col == $column) {
            $out[$col] = array_map('self::regex_replace', $rows);
        }
        else {
            $out[$col] = $rows;
        }
    }
    return $out;
}

Demo on 3v4l.org

【讨论】:

  • 我将如何指定是否应解析特定列或所有列? $engine->apply($document->content); 将解析所有列。但是假设我只想将规则应用于第一列:$engine->apply($document->content, 1);
  • @oliverbj 完全正确。如果您查看我的演示,您会发现我已经稍微修改了您的数据(将'Trevor' 添加到第 2 列的一行),因此您可以看到单列版本与整个表格版本一样有效。跨度>
  • 抱歉,在您编辑之前我正在查看您的代码。它就像一个魅力。
  • @oliverbj 是的,很抱歉。我没有正确考虑对$column 的更改,后来才意识到我把它塞进去了。
  • 如果它总是一个数组,只需将$col == $column替换为in_array($col, $column)
【解决方案3】:

只需循环它并对所有子数组执行正则表达式:

$content = json_decode($json, true);

$options = [
    'pattern' => '/Trevor/i',
    'replacement' => 'Oliver',
];
$engine = new regexTextReplace($options);
foreach($content as $key => $v){
    $columns[$key] = $engine->apply($content, $key);
}
var_dump($columns);

工作演示:
https://3v4l.org/Pk2rC

在“PHP”端而不是在类中循环的好处是,您仍然可以将正则表达式仅应用于一两个子数组。
如果你在类中循环,那么你需要传递更多的参数来限制循环或进行某种类型的数组切片。

【讨论】:

  • 那个循环可能属于类'apply函数
  • 谢谢安德烈亚斯!如果我没记错的话,这个循环默认会查看所有列,对吗?因为$keyapply() 函数的第二个参数。如果我将column => all 添加到我的$options 数组中,我是否可以将其传入?因为我希望用户要么解析所有列,要么只解析特定列。
  • @Nick 如果我将其直接放在 apply() 方法中,那么我将如何在 foreach 中调用实际的 apply() 方法?
  • 它既可以在类中使用,也可以在“PHP”代码中使用。虽然不确定变量名称。您的问题并未表明它们。
  • @oliverbj 如果将循环放在 apply 函数中,则不需要 foreach
猜你喜欢
  • 1970-01-01
  • 2018-08-24
  • 2019-01-02
  • 1970-01-01
  • 2018-05-25
  • 1970-01-01
  • 2017-01-14
  • 1970-01-01
  • 2019-01-21
相关资源
最近更新 更多