szczyglis/ultimate-chain-parser

一个综合模块化链内工具,用于高级文本数据处理和重新解析

v1.2.13 2024-08-26 14:59 UTC

This package is auto-updated.

Last update: 2024-09-26 15:19:26 UTC


README

版本: 1.2.13 | 构建: 2024.08.26 | PHP: ^7.2.5|^8.0

终极链解析器 - 基于链流程的解析器

终极链解析器是一个模块化包,旨在进行文本数据的链式处理,将其转换为结构化输出。 应用概念基于使用可配置的数据处理模块,以迭代的方式连续处理数据。执行链中的每个模块按顺序访问前一个模块的输出,并将其用作输入。

如何安装

composer require szczyglis/ultimate-chain-parser

终极链解析器可以用作哪些目的?

  • 将不一致的行或列分割的数据处理成标准格式(例如,CSV)。
  • 根据特定复杂模式重新解析数据。
  • 创建易于插入数据库或导入到Excel等软件的数据集。
  • 执行复杂的文本操作。
  • ...以及许多其他任务。

实时演示: https://szczyglis.dev/ultimate-chain-parser

parser2

特性

  • 将混乱排列的数据重新解析为结构化、干净的数据集(例如,CSV)
  • 解析来自网站、Word文档或PDF的混乱或损坏的数据
  • 按顺序运行预配置的工具(插件)
  • 执行复杂的文本数据处理
  • 使用在定义序列中执行的编程正则表达式解析复杂数据
  • 具有易于使用且功能强大的配置系统
  • 通过将任务分割成更小的、单独的工具来执行操作,每个工具与其他工具合作执行不同的任务批次
  • 包括可以单独工作或一起工作的工具:解析器、清洁器、限制器和替换器
  • 提供基于插件系统的模块化结构,每个元素均可通过自定义实现进行扩展或替换;每个组件都有自己的接口,用于扩展功能或替换现有的组件
  • 提供多个可扩展组件:配置提供者、输入数据读取器、数据解析器、渲染器、记录器等
  • 包括基于HTML/AJAX的配置器应用程序,用于实时测试和配置
  • 具有命令行工具,便于使用
  • 易于与现代框架(如Symfony)集成

要求

动作示例

需要处理的示例文本数据

123
terminator
schwarzenegger

action movie

very good


456
titanic

dicaprio


same director
                  

看起来很糟糕,对吧?终极链解析器可以将这种不一致排列的数据转换成结构化格式,如CSV、JSON、原始PHP数组或用户容易定义的任何其他模式

123,terminator,schwarzenegger,action movie very good
456,titanic,dicaprio,same director
[
    [
        {
            "id": "123",
            "title": "terminator",
            "actor": "schwarzenegger",
            "description": "action movie very good"
        },
        {
            "id": "456",
            "title": "titanic",
            "actor": "dicaprio",
            "description": "same director"
        }
    ]
]

上述CSV和JSON数据完全自动生成,仅使用了解析器输入中提供的少量配置选项。操作背后的主要概念是按顺序运行一系列处理工具(称为插件)。每个随后启动的过程都会访问链中上一个过程的输出。这些链元素可以自由配置不同的选项。配置可以通过多种方式完成:直接从您的代码中运行链解析器,从外部文件加载配置并通过命令行运行,或者完全实时地使用包含在包中的基于Ajax的配置器。最终链解析器还可以直接返回从分析数据(以PHP数组或JSON数据形式)准备好的未解析的(已分析的)数据集。

安装

Composer / packagist

composer require szczyglis/ultimate-chain-parser

手动安装

  • 下载zip包并解压。
  • 在项目目录中运行composer install以安装依赖项。
  • 在您的应用程序中包含Composer自动加载器并实例化ChainParser对象。

使用示例

  <?php

  // app.php

  require  __DIR__.'/vendor/autoload.php';

  use Szczyglis\ChainParser\ChainParser;
  use Szczyglis\ChainParser\Input\TextInput;
  use Szczyglis\ChainParser\Options\ArrayOptions;

  $parser = new ChainParser();
  $parser->setInput(new TextInput('some text data that needs to be parsed'));
  $parser->add('parser', new ArrayOptions([
    // options here
  ]); 
  $parser->run();

  $result = $parser->renderOutput();
  $log = $parser->renderLog();

  echo $result;

实时示例

前往https://szczyglis.dev/ultimate-chain-parser运行在线演示,或运行包中包含的example.php以在实时模式下打开基于Ajax的演示。在您看到的页面上,您将找到描述的选项,您将能够手动配置链时使用这些选项。

向链中添加元素

手动向链中添加元素非常简单

  $parser = new ChainParser();  
  $parser
    ->add('cleaner', new ArrayOptions([
        //options
    ])
    ->add('parser', new ArrayOptions([
        //options
    ])
    ->add('limiter', new ArrayOptions([
        //options
    ]); 
  
  $parser->run();

上述代码向链中添加了3个具有定义工具(称为插件)的新元素。这些元素中的每一个都会在之前元素的输出上操作。选项作为第二个参数传递,封装在选项提供器类中。您可以将元素以任何顺序和数量组合,直到达到预期的结果。

不需要按照上述方式手动添加元素。您可以使用预定义的配置来编程构建定义的链。

配置、选项和用法

工具:解析器

应用程序的主要工具,用于根据特定的模式和规则解析数据。

选项

- use_dataset - 布尔型启用在由前一个元素准备的数据集上操作,而不是其解析后的输出。这允许在元素之间传递已准备好的数据集。当从原始输入开始时,不要在链的第一个元素中使用此选项,因为没有来自前一个元素的准备好的数据集。

- regex_match - 数组一组正则表达式,用于将数据与相应的字段匹配。您可以为每个字段添加多个模式;如果提供了多个模式,则只需匹配一个(执行逻辑“或”操作)。此选项可以指定为文本(每行一个字段)或直接在PHP数组中。

语法: FIELDNAME:/REGEX/(每行)

示例(文本)

id:/^[\d]+$/
name:/^[^\d]+/
name:/[^\d]+$/

示例(数组)

  $options['regex_match'] = [
    'id' => [
       0 => '/^[\d]+$/',
    ],
    'name' => [
      0 => '/^[^\d]+/',
      1 => '/[^\d]+$/',
    ],
  ];

- regex_ignore_before - 数组一个正则表达式的列表,如果匹配(在应用“replace_filter_before”之前),将跳过匹配的数据块。这用于忽略匹配给定模式的块。您可以输入多个表达式,可以是文本形式(每个表达式占一行),也可以直接在PHP数组中。

语法: /REGEX/(每行)

示例(文本)

/^XYZ+$/
/^some unwanted data/

示例(数组)

  $options['regex_ignore_before'] = [
    0 => '/^XYZ+$/',
    1 => '/^some unwanted data/',
  ];

- regex_ignore_after - array 一个正则表达式列表,如果匹配(在应用 "replace_filter_before" 之后),将跳过匹配到的数据块。这用于忽略与给定模式匹配的块。您可以输入多个表达式,可以是每行一个文本形式的表达式,或者直接在 PHP 数组中输入。

语法:/REGEX/(每行一个)

示例(文本)

/^XYZ+$/
/^some unwanted data/

示例(数组)

  $options['regex_ignore_after'] = [
    0 => '/^XYZ+$/',
    1 => '/^some unwanted data/',
  ];

- replace_field_before - array 用于替换或预处理数据块的正则表达式列表,在尝试匹配给定的字段之前应用。这可以在每次匹配尝试之前预先过滤数据。您可以输入多个表达式,可以是每行一个文本形式的表达式,或者直接在 PHP 数组中输入。

语法: FIELDNAME:/REGEX/ => "REPLACED STRING"(每行一个模式)

示例(文本)

id:/^[\d]+$/ => 12345
name:/^([^\d]+)/ => $1
name:/^([A-Z]+)/ => abc$1

示例(数组)

  $options['replace_field_before'] = [
    'id' => [
      0 => [
        'pattern' => '/^[\d]+$/',
        'replacement' => '12345',
      ],        
    ],
    'name' => [
      0 => [
        'pattern' => '/^([^\d]+)/',
        'replacement' => '$1',
      ], 
      1 => [
        'pattern' => '/^([A-Z]+)/',
        'replacement' => 'abc$1',
      ],        
    ],
  ];

- replace_field_after - array 用于替换已匹配字段为另一个文本字符串的正则表达式列表。这可用于匹配字段的后续处理。您可以输入多个表达式,可以是每行一个文本形式的表达式,或者直接在 PHP 数组中输入。

语法: FIELDNAME:/REGEX/ => "REPLACED STRING"(每行一个模式)

示例(文本)

id:/^[\d]+$/ => 12345
name:/^([^\d]+)/ => $1

示例(数组)

  $options['replace_field_after'] = [
    'id' => [
      0 => [
        'pattern' => '/^[\d]+$/',
        'replacement' => '12345',
      ],        
    ],
    'name' => [
      0 => [
        'pattern' => '/^([^\d]+)/',
        'replacement' => '$1',
      ],        
    ],
  ];

- replace_block_before - array 用于替换或预先准备数据块的正则表达式列表,在尝试匹配之前应用于整个数据块。这可以在每次匹配尝试之前预先过滤数据。您可以输入多个表达式,可以是每行一个文本形式的表达式,或者直接在 PHP 数组中输入。

语法: /REGEX/ => "REPLACED STRING"(每行一个模式)。

示例(文本)

/^[\d]+$/ => 12345
/^([^\d]+)/ => $1

示例(数组)

  $options['replace_block_before'] = [
    0 => [
      'pattern' => '/^[\d]+$/',
      'replacement' => '12345',
    ]
    1 => [
      'pattern' => '/^([^\d]+)/',
      'replacement' => '$1',
    ],
  ];

- replace_block_after - array 用于替换已匹配块为另一个文本字符串的正则表达式列表。在匹配后应用于整个数据块,可用于匹配数据的后续处理。您可以输入多个表达式,可以是每行一个文本形式的表达式,或者直接在 PHP 数组中输入。

语法: /REGEX/ => "REPLACED STRING"(每行一个模式)

示例(文本)

/^[\d]+$/ => 12345
/^([^\d]+)/ => $1

示例(数组)

  $options['replace_block_after'] = [
    0 => [
      'pattern' => '/^[\d]+$/',
      'replacement' => '12345',
    ]
    1 => [
      'pattern' => '/^([^\d]+)/',
      'replacement' => '$1',
    ],
  ];

- fields - array 要匹配的字段列表。将字段名输入到您想要分割解析数据的字段中,例如,id、name、actor、description。字段应在一行中输入,用逗号(,)分隔,或作为字段数组。

语法: FIELDNAME1,FIELDNAME2,FIELDNAME3,FIELDNAME4...

示例(文本)

id,title,actor,description

示例(数组)

  $options['fields'] = [
    'id',
    'title',
    'actor',
    'description',
  ];

- output_fields - array 从上面的列表中匹配并在输出中显示的字段列表,例如,id、name、actor。字段应在一行中输入,用逗号(,)分隔,或作为字段数组。

语法: FIELDNAME1,FIELDNAME2,FIELDNAME3,FIELDNAME4...

示例(文本)

id,title,actor,description

示例(数组)

  $options['output_fields'] = [
    'id',
    'title',
    'actor',
    'description',
  ];

- sep_input_rowset - string 当分割为行集时,输入的行集分隔符,根据预期的输出分布使用,例如,\n。

- sep_input_row - string 当分割为行时,输入数据的行分隔符,根据预期的输出分布使用,例如,\n。

- sep_input_column - string 当分割为列时,输入数据的列分隔符,根据预期的输出分布使用,例如,逗号(,)。

- sep_output_rowset - string 在从行集连接结果时,输出中行集的分隔符,根据所需的输出格式使用,例如,\n。

- sep_output_row - string 在从行连接结果时,输出中的行分隔符,根据所需的输出格式使用,例如,\n。

- sep_output_column - string 在从列连接结果时,输出中的列分隔符,根据所需的输出格式使用,例如,逗号(,)。

- empty_field_placeholder - string 如果匹配到的字段为空,则用占位符替换给定字段。如果您不想使用任何占位符,请留空。

- is_debug - 布尔值,如果为 TRUE,则将调试信息追加到每行输出中。

- is_empty_field_placeholder - 布尔值,如果为 TRUE,则将匹配字段中的空格替换为 empty_placeholder 选项中指定的字符串。

工具:cleaner

一个用于清理、消毒和预处理输入数据以供进一步处理的工具。

选项

- use_dataset - 布尔值,启用对由前一个元素准备的数据集的操作,而不是其解析输出。这允许在不同元素之间传输已准备好的数据集。在从原始输入开始时,不要在链的第一个元素中使用此功能,因为没有来自前一个元素的准备好的数据集。

- trim - 布尔值,将 trim() 函数应用于每个块。

- clean_blocks - 布尔值,删除空块。

- fix_newlines - 布尔值,将所有 \r\n 替换为 \n。

- strip_tags - 布尔值,将 strip_tags() 函数应用于所有内容。

- sep_input_rowset - string 当分割为行集时,输入的行集分隔符,根据预期的输出分布使用,例如,\n。

- sep_input_row - string 当分割为行时,输入数据的行分隔符,根据预期的输出分布使用,例如,\n。

- sep_input_column - string 当分割为列时,输入数据的列分隔符,根据预期的输出分布使用,例如,逗号(,)。

- sep_output_rowset - string 在从行集连接结果时,输出中行集的分隔符,根据所需的输出格式使用,例如,\n。

- sep_output_row - string 在从行连接结果时,输出中的行分隔符,根据所需的输出格式使用,例如,\n。

- sep_output_column - string 在从列连接结果时,输出中的列分隔符,根据所需的输出格式使用,例如,逗号(,)。

工具:limiter

一个根据特定模式和规则限制生成或接收数据量的工具。它还可以用于删除数据。

选项

- use_dataset - 布尔型启用在由前一个元素准备的数据集上操作,而不是其解析后的输出。这允许在元素之间传递已准备好的数据集。当从原始输入开始时,不要在链的第一个元素中使用此选项,因为没有来自前一个元素的准备好的数据集。

- data_mode - 字符串 [rowset|row|column] - 选择其他选项将操作所在的维度。

- interval_allow - 整数,限制输出到与给定间隔匹配的块。默认为 1。

- range_allow - 数组,限制输出到与指定范围匹配的块;留空以允许所有块。指定范围(以逗号分隔),索引从 0 开始。

语法: 整数1, 整数2, 整数3-整数4,integer5-,-integer6 [...]

示例(文本)

0, 3, 5-7, 15-, -20

示例(数组)

  $options['range'] = [
    0 => 0,
    1 => 3,
    2 => [
      'from' => 5
      'to' => 7,
    ],
    3 => [
      'from' => 15,
      'to' => null,
    ],
    4 => [
      'from' => null,
      'to' => 20,
    ],
  ];

- regex_allow - 数组,限制输出到与给定正则表达式匹配的块。您可以在新的一行中输入多个表达式。

语法: /REGEX/(每行)

示例(文本)

/^XYZ+$/
/^ZYX+$/

示例(数组)

  $options['regex_allow'] = [
    0 => '/^XYZ+$/',
    1 => '/^ZYX+$/',
  ];

- interval_deny - 整数,限制输出到不匹配给定间隔的块。默认为 1。

- range_deny - 数组,限制输出中的块不匹配指定的范围。留空以允许所有块,或指定范围(以逗号分隔)。索引从 0 开始。

语法: 整数1, 整数2, 整数3-整数4,integer5-,-integer6 [...]

示例(文本)

0, 3, 5-7, 15-, -20

示例(数组)

  $options['range'] = [
    0 => 0,
    1 => 3,
    2 => [
      'from' => 5
      'to' => 7,
    ],
    3 => [
      'from' => 15,
      'to' => null,
    ],
    4 => [
      'from' => null,
      'to' => 20,
    ],
  ];

- regex_deny - 数组,限制输出到不匹配给定正则表达式的块。您可以在新的一行中输入多个表达式。

语法: /REGEX/(每行)

示例(文本)

/^XYZ+$/
/^ZYX+$/

示例(数组)

  $options['regex_deny'] = [
    0 => '/^XYZ+$/',
    1 => '/^ZYX+$/',
  ];

- sep_input_rowset - string 当分割为行集时,输入的行集分隔符,根据预期的输出分布使用,例如,\n。

- sep_input_row - string 当分割为行时,输入数据的行分隔符,根据预期的输出分布使用,例如,\n。

- sep_input_column - string 当分割为列时,输入数据的列分隔符,根据预期的输出分布使用,例如,逗号(,)。

- sep_output_rowset - string 在从行集连接结果时,输出中行集的分隔符,根据所需的输出格式使用,例如,\n。

- sep_output_row - string 在从行连接结果时,输出中的行分隔符,根据所需的输出格式使用,例如,\n。

- sep_output_column - string 在从列连接结果时,输出中的列分隔符,根据所需的输出格式使用,例如,逗号(,)。

工具:replacer

一个根据定义的模式和规则将特定批次数据转换为其他格式的工具。

选项

- use_dataset - 布尔型启用在由前一个元素准备的数据集上操作,而不是其解析后的输出。这允许在元素之间传递已准备好的数据集。当从原始输入开始时,不要在链的第一个元素中使用此选项,因为没有来自前一个元素的准备好的数据集。

- data_mode - 字符串 [rowset|row|column] 选择其他选项将操作所在的维度。

- regex - 数组,用于替换适当字符串的正则表达式。您可以在新的一行中输入多个模式。

语法: /REGEX/ => "REPLACED STRING"(每行一个模式)

示例(文本)

/^[\d]+$/ => 12345
/^([^\d]+)/ => $1

示例(数组)

  $options['regex'] = [
    0 => [
      'pattern' => '/^[\d]+$/',
      'replacement' => '12345',
    ]
    1 => [
      'pattern' => '/^([^\d]+)/',
      'replacement' => '$1',
    ],
  ];

- interval - 整数,限制替换到特定间隔。默认为 1。

- range - 数组,限制替换到指定的范围;留空以替换所有块。指定范围(以逗号分隔)。索引从 0 开始。

语法: 整数1, 整数2, 整数3-整数4,integer5-,-integer6 [...]

示例(文本)

0, 3, 5-7, 15-, -20

示例(数组)

  $options['range'] = [
    0 => 0,
    1 => 3,
    2 => [
      'from' => 5
      'to' => 7,
    ],
    3 => [
      'from' => 15,
      'to' => null,
    ],
    4 => [
      'from' => null,
      'to' => 20,
    ],
  ];

- sep_input_rowset - string 当分割为行集时,输入的行集分隔符,根据预期的输出分布使用,例如,\n。

- sep_input_row - string 当分割为行时,输入数据的行分隔符,根据预期的输出分布使用,例如,\n。

- sep_input_column - string 当分割为列时,输入数据的列分隔符,根据预期的输出分布使用,例如,逗号(,)。

- sep_output_rowset - string 在从行集连接结果时,输出中行集的分隔符,根据所需的输出格式使用,例如,\n。

- sep_output_row - string 在从行连接结果时,输出中的行分隔符,根据所需的输出格式使用,例如,\n。

- sep_output_column - string 在从列连接结果时,输出中的列分隔符,根据所需的输出格式使用,例如,逗号(,)。

在命令行(PHP CLI)中运行

该软件包在 Command 目录中包含一个 Symfony 命令。您可以使用 cmd.php 脚本运行该命令。

在 CLI 中的用法

./cmd.php chainparser /path/to/data /path/to/config.yaml [--options]

参数

/path/to/data - 解析文本数据的文件路径。

/path/to/config.yaml - YAML 配置文件的路径。

选项

--log=0 - 禁用日志输出

--data=0 - 禁用原始数据输出

该软件包包含 2 个示例文件

  • example.txt

  • example.yaml

您可以使用这些示例文件进行测试

./cmd.php chainparser ./example.txt ./example.yaml

禁用日志和数据输出,仅输出解析结果

./cmd.php chainparser ./example.txt ./example.yaml --log=0 --data=0

将输出结果存储在名为 output.txt 的文件中

./cmd.php chainparser ./example.txt ./example.yaml --log=0 --data=0 > output.txt

配置选项

您可以使用包含的配置提供者或编写自己的。目前包含两个配置提供者

  • ArrayConfig - 与直接从 PHP 数组提供的配置一起使用。

  • YamlConfig - 与从YAML文件读取的配置一起工作。

用法

<?php

namespace App;

use Szczyglis\ChainParser\Config\YamlConfig;


//...

$parser->setConfig(new YamlConfig('/path/to/config.yaml'));

或者

<?php

namespace App;

use Szczyglis\ChainParser\Config\ArrayConfig;

//...

$parser->setConfig(new ArrayConfig([
  'key' => 'value',
]));

可用的配置选项

- full_output - 布尔值,默认:false。如果为true,则将所有链元素的输出都渲染到输出中。如果为false,则仅渲染最后一个结果。

- log_file - 字符串,使用PsrLogger(Monolog)时的日志文件绝对路径。

- no_log - bool,如果为true,则禁用日志记录。

日志记录器

您可以使用包含的日志记录器或编写自己的。该软件包包括三个不同的日志记录器

  • ArrayLogger - 将所有内容记录到一个PHP数组中。

  • ConsoleLogger - 将输出记录到CLI控制台。

  • PsrLogger - 使用Monolog Logger将日志存储在文件中。

用法

<?php

namespace App;

use Szczyglis\ChainParser\Logger\ArrayLogger;
use Szczyglis\ChainParser\Logger\PsrLogger;
use Szczyglis\ChainParser\Logger\ConsoleLogger;


//...

$parser->addLogger(new ArrayLogger());
$parser->addLogger(new PsrLogger('/path/to/logfile'));
$parser->addLogger(new ConsoleLogger());

您可以一次性注册多个日志记录器;输出将同时发送到所有日志记录器。

访问生成的日志非常简单

  ...
$parser->run();

$log = $parser->renderLog();

dump($log);

或者,如果您想获取原始(未渲染/解析)的日志数据,请使用

$parser->run();

$output = $parser->getOutput();
$log = $output->get('logs');
dump($log);

扩展链解析器

该概念基于完全模块化,允许您通过自己的解析器和功能扩展软件包。每个元素都可以根据您的需求进行适配,以解决您具体的问题。

配置提供者

配置提供者负责读取和解析配置。软件包中包含一些基本的配置提供者,但您可以轻松创建自己的。

配置提供者位于:Szczyglis\ChainParser\Config 命名空间。

包含的配置提供者

  • ArrayConfig - 从构造函数参数传递的PHP数组中读取配置。

  • YamlConfig - 从YAML文件中读取配置(需要将文件的路径作为构造函数参数传递)。

如何创建自己的配置提供者

  • 实现接口 Szczyglis\ChainParser\Contract\ConfigInterface
  • 使用setConfig()方法附加您的配置提供者

示例

<?php

// MyConfig.php

namespace App;

use Szczyglis\ChainParser\Contract\ConfigInterface;
use Szczyglis\ChainParser\Helper\AbstractInput;

class MyConfig implements ConfigInterface
{
  private $config;

  public function __construct(array $config)
  {
    $this->config = $config;
  }

  public function get(string $key)
  {
    if (array_key_exists($key, $this->config)) {
      return $this->config[$key];
    }   
  }

  public function set(string $key, $value)
  {
    $this-config[$key] = $value;    
  }

  public function has(string $key)
  {
    if (array_key_exists($key, $this->config)) {
      return true;
    }   
  }

  public function all()
  {
    return $this->config;
  }
}
<?php

// app.php

use Szczyglis\ChainParser\ChainParser;
use App\MyConfig;

$parser = new ChainParser();
$parser->setConfig(new MyConfig([
  'foo' => 'bar',
]));

// rest of initialization, config, etc...

$parser->run();
$parser->renderOutput();

输入数据提供者

输入数据提供者负责读取输入数据。软件包中包含一些基本的输入数据提供者,但您可以轻松创建自己的。

输入数据提供者位于:Szczyglis\ChainParser\Input 命名空间。

包含的输入数据提供者

  • TextInput - 直接从构造函数参数传递的文本字符串中读取输入数据。

  • FileInput - 从文件中读取输入数据(需要将文件的路径作为构造函数参数传递)。

如何创建自己的输入数据提供者

  • 实现接口 Szczyglis\ChainParser\Contract\InputInterface
  • 可选地扩展抽象辅助类 Szczyglis\ChainParser\Helper\AbstractInput
  • 使用setInput()方法附加您的输入数据提供者

示例

<?php

// MyInput.php

namespace App;

use Szczyglis\ChainParser\Contract\InputInterface;
use Szczyglis\ChainParser\Helper\AbstractInput;

class MyInput extends AbstractInput implements InputInterface
{
  private $input;
  private $dataset = [];

  public function __construct(string $input)
  {
    $this->input = $input;
  }

  public function getInput()
  {
    return $this->input;
  }

  public function getDataset()
  {
    return $this->dataset;
  }
}
<?php

// app.php

use Szczyglis\ChainParser\ChainParser;
use App\MyInput;

$parser = new ChainParser();
$parser->setInput(new MyInput('some input data here...'));

// rest of initialization, config, etc...

$parser->run();
$parser->renderOutput();

日志记录器

日志记录器负责从插件中记录数据。软件包中包含一些基本的日志记录器,但您可以轻松创建自己的。

日志记录器位于:Szczyglis\ChainParser\Logger 命名空间。

包含的日志记录器

  • ArrayLogger - 直接将日志写入PHP数组。

  • PsrLogger - 使用Monolog将日志写入文件。

  • ConsoleLogger - 直接在控制台显示日志。

如何创建自己的日志记录器

  • 实现接口 Szczyglis\ChainParser\Contract\LoggerInterface
  • 可选地扩展抽象辅助类 Szczyglis\ChainParser\Helper\AbstractLogger
  • 使用addLogger()方法添加日志记录器

示例

<?php

// MyLogger.php

namespace App;

use Szczyglis\ChainParser\Contract\LoggerInterface;
use Szczyglis\ChainParser\Helper\AbstractLogger;

class MyLogger extends AbstractLogger implements LoggerInterface
{
  private $logs;

  public function addMessage(string $message, array $data)
  {
    $this->logs[] = $message;
  }

  // ...rest of code
}
<?php

// app.php

use Szczyglis\ChainParser\ChainParser;
use App\MyLogger;

$parser = new ChainParser();
$parser->addLogger(new MyLogger());

// rest of initialization, config, etc...

$parser->run();
$parser->renderOutput();

选项提供者

选项提供者负责读取、解析和提供插件选项。软件包中包含一些基本的选项提供者,但您可以轻松创建自己的。

选项提供者位于:Szczyglis\ChainParser\Options 命名空间。

包含的选项提供者

  • ArrayOptions - 直接从构造函数参数传递的PHP数组中读取选项。

  • FormOptions - 解析以文本或从HTML表单中传递的选项。

如何创建自己的选项提供者

  • 实现接口 Szczyglis\ChainParser\Contract\OptionsInterface
  • 可选地扩展抽象辅助类 Szczyglis\ChainParser\Helper\AbstractOptions
  • 使用自己的选项提供者初始化插件

示例

<?php

// MyOptions.php

namespace App;

use Szczyglis\ChainParser\Contract\OptionsInterface;
use Szczyglis\ChainParser\Helper\AbstractOptions;

class MyOptions extends AbstractOptions implements OptionsInterface
{
  private $options;

  public function __construct(string $options)
  {
    $this->options = $options;
  }

  public function get(string $key)
  {
    if (array_key_exists($key, $this->options)) {
      return $this->options[$key];
    }   
  }

  public function has(string $key)
  {
    if (array_key_exists($key, $this->options)) {
      return true;
    }   
  }

  public function all()
  {
    return $this->options;
  }
}
<?php

// app.php

use Szczyglis\ChainParser\ChainParser;
use App\MyOptions;

$parser = new ChainParser();
$parser->add('parser', new MyOptions([
    'foo' => 'bar',
]));

// rest of initialization, config, etc...

$parser->run();
$parser->renderOutput();

选项解析器

选项解析器负责解析选项,例如,当选项通过HTML表单提供并需要解析为数组时。包中包含一些基础选项解析器,但您可以轻松地创建自己的。

选项解析器位于 Szczyglis\ChainParser\OptionResolver 命名空间中。

包含的选项解析器

  • SingleLineResolver - 解析单行中的选项。

  • MultiLineResolver - 解析多行中的更复杂语法。

  • RangeResolver - 解析基于范围的选项,例如,1,2,8-10。

如何创建自己的选项解析器,例如用于自己的插件配置

  • 实现接口 Szczyglis\ChainParser\Contract\OptionResolverInterface
  • 使用 addResolver() 方法注册选项解析器

示例

<?php

// MyResolver.php

namespace App;

use Szczyglis\ChainParser\Contract\OptionResolverInterface;
use Szczyglis\ChainParser\Helper\AbstractInput;

class MyResolver implements OptionResolverInterface
{
  public function resolve(string $key, $value)
  {
    return explode(';', $value);    
  }

  public function getName(): string
  {
    return 'my_resolver';
  }
}
<?php

// MyPlugin.php


class MyPlugin ...

public function run(): bool
{
  // ...
}

public function registerOptions(): array
{
    return [
        'my_resolver' => [  // resolver name
            'foo', // option name
        ],
    ];
}
<?php

// app.php

use Szczyglis\ChainParser\ChainParser;
use Szczyglis\ChainParser\Options\FormOptions;
use App\MyResolver;

$parser = new ChainParser();
$parser->addResolver(new MyResolver());
$parser->add('parser', new FormOptions([
    'foo' => 'bar1;bar2;bar3', // option "foo" will be parsed with your resolver
]));

// rest of initialization, config, etc...

$parser->run();
$parser->renderOutput();

插件

插件是应用程序的核心。它们是沿着链运行并在数据上操作的工具。每个插件都可以与链中前一个插件的原始输入和输出一起工作。还有一些称为 Workers 的特殊类,可以帮助您组织代码并将代码分解为不同的“子进程”。Worker与主插件共享相同的数据集,并且可以快速与插件交换数据。您可以使用 registerWorker 方法轻松注册自己的Worker。

插件位于 Szczyglis\ChainParser\Plugin 命名空间中。

包含的插件

  • Parser - 应用程序的主要工具,用于根据特定的模式和规则解析数据。

  • Cleaner - 清理输入数据的工具,对数据进行净化并预处理以供进一步处理。

  • Limiter - 根据特定的模式和规则限制和删除生成或接收的数据的工具。

  • Replacer - 根据特定的模式和规则将特定的数据批量转换为其他格式的工具。

如何创建自己的插件

  • 实现接口 Szczyglis\ChainParser\Contract\PluginInterface
  • 扩展抽象辅助类 Szczyglis\ChainParser\Helper\AbstractPlugin
  • 将插件添加到链中

示例

<?php

// MyPlugin.php

namespace App;

use Szczyglis\ChainParser\Contract\PluginInterface;
use Szczyglis\ChainParser\Contract\LoggableInterface;
use Szczyglis\ChainParser\Helper\AbstractPlugin;

class MyPlugin extends AbstractPlugin implements PluginInterface, LoggableInterface
{
  const NAME = 'my_plugin';

  public function run(): bool
  {
    $dataset = $this->getDataset(); // get previous data or from input

    // do something with data
    
    $this->setDataset($dataset); // return data to next element or to output

    return true;
  }

  public function getName(): string
  {
    return self::NAME;
  }
}
<?php

// app.php

use Szczyglis\ChainParser\ChainParser;
use Szczyglis\ChainParser\Input\TextInput;
use Szczyglis\ChainParser\Options\ArrayOptions;
use App\MyPlugin;

$parser = new ChainParser();
$parser->addPlugin(new MyPlugin());
$parser->setInput(new TextInput('foo'));
$parser->add('my_plugin', new ArrayOptions([
    'option' => 'value',
]));

// rest of initialization, config, etc...

$parser->run();
echo $parser->renderOutput(); // returns "Hello foo"

创建自己的Worker

<?php

// MyWorker.php

namespace App;

use Szczyglis\ChainParser\Contract\WorkerInterface;
use Szczyglis\ChainParser\Contract\LoggableWorkerInterface;
use Szczyglis\ChainParser\Helper\AbstractWorker;

class MyWorker extends AbstractWorker implements WorkerInterface, LoggableWorkerInterface
{
  public function doSomeJob()
  {
    $var = $this->getVar('foo');
    $var++;
    $this->setVar('foo', $var);
  }
}
<?php

// MyPlugin.php

namespace App;

use Szczyglis\ChainParser\Contract\PluginInterface;
use Szczyglis\ChainParser\Contract\LoggableInterface;
use Szczyglis\ChainParser\Helper\AbstractPlugin;

class MyPlugin extends AbstractPlugin implements PluginInterface, LoggableInterface
{
  const NAME = 'my_plugin';

  public function run(): bool
  {
    $worker = $this->getWorker('my_worker');

    $foo = 10;
    $this->setVar('foo', $foo);

    $worker->doSomeJob();

    $bar = $this->getVar('foo');

    echo $bar; // will display 11

    return true;
  }

  public function registerWorkers(): array
  {
    return [
      'my_worker' => new MyWorker(),
    ];
  }
}

Worker在给定的 registerWorkers() 方法中注册和初始化。如上面的示例所示,Worker和插件有一个共同的容器,用于临时数据,用于在插件和Worker之间交换变量。

$this->setVar('foo', $bar); // sets var foo 
$foo = $this->getVar('foo'); // gets var foo

从插件和工作器级别访问输入和输出数据如下

<?php

// MyPlugin.php

class MyPlugin ...

public function run(): bool
{
  $input = $this->getPrev('output'); // output from previous element in chain (or raw input if Plugin is first in chain)
  $prevDataset = $this->getPrev('dataset'); // output data (as `array`, not parsed) from previous element in chan
  $dataset = $this->get('dataset'); // get current dataset or output from previous element

  $rawInput = $this->get('input'); // raw, initial input

  $i = $this->getIteration(); // current iteration index in chain
  $config = $this->getConfig(); // returns config object

  $optionValue = $this->getOption('key'); // returns option value by key
  $allOptions = $this->getOptions(); // returns all options (as key => value array)

  $dataset = $this->getDataset(); // alias for $this->get('dataset');

  return true;
}

在工具内设置输出数据

<?php

// MyPlugin.php


class MyPlugin ...

public function run(): bool
{
  $input = $this->getPrev('output');  // get parsed previous output or current input
  $dataset = $this->getDataset(); // get data form previous output or current input

  // do manipulation on data

  $this->setDataset($dataset);  // data will be sent to the next element in the chain as its input

  return true;
}

插件和工作器内的辅助工具

您可以使用由 AbstractPluginAbstractWorker 抽象类提供的某些包含的辅助工具。当您从它们扩展类时,您将有权访问一些有用的方法

$this->isPattern($pattern): bool - 检查 $pattern 是否是有效的正则表达式模式。

$this->checkPatterns(array $patterns, string $string): bool - 检查至少一个提供的正则表达式模式是否与字符串匹配。

$this->applyPatterns(array $patterns, string $string): string - 将任何替换模式应用到给定的字符串上。

$this->explode(string $separator, ?string $input): array - 对 explode() 的包装,允许使用正则表达式作为分隔符进行拆分。

$this->implode(string $joiner, array &$ary): string - 对 implode() 的包装。

$this->strReplace($from, $to, $data): string - 对 str_replace() 的包装。

$this->stripTags($data, $tags = null): string - 对 strip_tags() 的包装。

$this->trim($input): string - 对 trim() 的包装。

$this->inRange(array $ranges, int $i): bool - 检查一个数字是否匹配给定的范围。

$this->makeDataset(?string $input, string $sepRowset, string $sepRow, string $sepCol): array - 使用给定的分隔符将字符串输入转换为三维数据集数组。

$this->packDataset(array $dataset, string $sepRowset, string $sepRow, string $sepCol): string - 从数据集构建解析后的结果。

$this->iterateDataset(array $dataset, callable $callback): array - 对数据集中的每个块应用回调函数,并返回经过回调函数修改的数据集。示例

  $dataset = $this->iterateDataset($dataset, function($value) {
      return str_replace('A', 'B', $value);
  });

这样做将会在数据集中的每个元素中将字符A替换为字符B。

检查包含在包中的插件代码以查看实时示例是一个好主意。

注册需要先解析的选项

如果您需要使用需要先解析数据(例如,转换为 array)的选项,例如,使用现成的选项解析器或创建自己的解析器。要使用适当的选项解析器注册选项,请使用 registerOptions() 方法返回其名称。从现在起,它将由分配的解析器进行解析。数组应包括解析器的名称以及分配给它的选项列表。使用示例

<?php

// MyPlugin.php


class MyPlugin ...

public function run(): bool
{
  // ...
}

public function registerOptions(): array
{
    return [
        'multiline' => [  // resolver name
            'my_pattern', // option name
        ],
        'range' => [ // resolver name
            'my_range', // option name
        ],
    ];
}

包含的解析器

  • singleline - 解析单行参数,例如 key: value => assignment/replacement

  • multiline - 解析多行参数,其中 key: value => assignment/replacement 放在单独的行上。

  • range - 解析范围参数,例如:1,5,10-20,15-,-80

记录消息

从插件和工作者级别,您可以使用注册的记录器访问日志事件。用于此目的的方法是 $this->log()。要使用事件记录,必须实现以下接口

  • 在插件中:Szczyglis\ChainParser\Contract\LoggableInterface
  • 在工作者中:Szczyglis\ChainParser\Contract\LoggableWorkerInterface

使用示例

<?php

// MyPlugin.php

namespace App;

use Szczyglis\ChainParser\Contract\PluginInterface;
use Szczyglis\ChainParser\Contract\LoggableInterface;
use Szczyglis\ChainParser\Helper\AbstractPlugin;

class MyPlugin extends AbstractPlugin implements PluginInterface, LoggableInterface
{
  const NAME = 'my_plugin';

  public function run(): bool
  {
    $this->log('some message');

    return true;
  }
}
<?php

// MyWorker.php

namespace App;

use Szczyglis\ChainParser\Contract\WorkerInterface;
use Szczyglis\ChainParser\Contract\LoggableWorkerInterface;
use Szczyglis\ChainParser\Helper\AbstractWorker;

class MyWorker extends AbstractWorker implements WorkerInterface, LoggableWorkerInterface
{
  public function doSomeJob()
  {
    $this->log('some message');
  }
}

渲染器

渲染器负责显示输出。包中包含一些基础渲染器,但您也可以轻松创建自己的。

渲染器位于 Szczyglis\ChainParser\Renderer 命名空间。

包含的渲染器

  • TextRenderer - 将输出解析为 TXT/HTML 格式

  • ConsoleRenderer - 将输出发送到控制台

如何创建自己的渲染器

  • 实现接口 Szczyglis\ChainParser\Contract\RendererInterface
  • 可选地扩展抽象辅助类 Szczyglis\ChainParser\Helper\AbstractRenderer
  • 使用 setRenderer() 方法设置渲染器

示例

<?php

// MyRenderer.php

namespace App;

use Szczyglis\ChainParser\Contract\RendererInterface;
use Szczyglis\ChainParser\Helper\AbstractRenderer;

class MyRenderer extends AbstractRenderer implements RendererInterface
{
  public function renderOutput(?array $options = [])
  {
    foreach ($this->output as $item) {
      dump($item->get('output'));
    }
  }

  public function renderData(?array $options = [])
  {
    foreach ($this->output as $item) {
      dump($item->get('data'));
    }
  }

  public function renderLog(?array $options = [])
  {
    foreach ($this->output as $item) {
      $loggers = $item->getLog();
      foreach ($loggers as $lines) {
        foreach ($lines as $line) {
          dump($line);
        }       
      }
    }
  }
} 
<?php

// app.php

use Szczyglis\ChainParser\ChainParser;
use App\MyRenderer;

$parser = new ChainParser();
$parser->preventDefault(); // unregister default renderer
$parser->setRenderer(new MyRenderer()); // set your own

// rest of initialization, config, etc...

$parser->run();
$parser->renderOutput(); // will display dumped output from your renderer
$parser->renderData(); // will display dumped output from your renderer
$parser->renderLog(); // will display dumped output from your renderer

导出配置

您可以在任何时间导出当前正在运行配置,包括整个链及其选项。为此,请使用配置生成器

<?php

// app.php

require __DIR__ . '/vendor/autoload.php';

use Szczyglis\ChainParser\ChainParser;
use Szczyglis\ChainParser\Core\ConfigGenerator;

$parser = new ChainParser;

// initialization, configuration, etc...

$parser->run();

$myConfig = (new ConfigGenerator())->build($parser, 'yaml'); // yaml | json

dump($myConfig); // displays configuration in Yaml format

您可以使用配置加载器 Szczyglis\ChainParser\Config\YamlConfig 加载导出并保存的配置。

实时演示: https://szczyglis.dev/ultimate-chain-parser

src

变更日志

1.0.0 - 发布第一个版本。 (2022-04-22)

1.0.4 - 在演示模式下增加了限制,修复了文档。 (2022-04-22)

1.2.6 - 添加了完整的数据集共享,删除了擦除器和拆分插件(它们的作用被限制器接管),通过自由指定每个维度的每个分隔符(行集、行、列)来添加数据集外观的配置。 (2022-04-23)

1.2.10 - 更新 PHPDoc,更新了示例 YAML 配置。 (2022-04-25)

1.2.11 - 更新 composer.json。 (2022-04-28)

1.2.12 - 改进了文档(2024-08-26)

1.2.13 - 在文档和示例应用中扩展了选项描述(2024-08-26)

Ultimate Chain Parser 可以免费使用,但如果您喜欢它,可以通过购买咖啡支持我的工作 ;)

https://www.buymeacoffee.com/szczyglis

享受吧!

MIT 许可证 | 2022 年 3 月 Marcin 'szczyglis' Szczygliński

https://github.com/szczyglis-dev/ultimate-chain-parser

https://szczyglis.dev/ultimate-chain-parser

联系方式:szczyglis@protonmail.com