szczyglis / ultimate-chain-parser
一个综合模块化链内工具,用于高级文本数据处理和重新解析
Requires
- php: ^7.2.5 || ^8.0
- monolog/monolog: ^2.1
- symfony/console: ^5.1
- symfony/http-foundation: ^5.1
- symfony/var-dumper: ^5.1
- symfony/yaml: ^5.1
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
特性
- 将混乱排列的数据重新解析为结构化、干净的数据集(例如,CSV)
- 解析来自网站、Word文档或PDF的混乱或损坏的数据
- 按顺序运行预配置的工具(插件)
- 执行复杂的文本数据处理
- 使用在定义序列中执行的编程正则表达式解析复杂数据
- 具有易于使用且功能强大的配置系统
- 通过将任务分割成更小的、单独的工具来执行操作,每个工具与其他工具合作执行不同的任务批次
- 包括可以单独工作或一起工作的工具:解析器、清洁器、限制器和替换器
- 提供基于插件系统的模块化结构,每个元素均可通过自定义实现进行扩展或替换;每个组件都有自己的接口,用于扩展功能或替换现有的组件
- 提供多个可扩展组件:配置提供者、输入数据读取器、数据解析器、渲染器、记录器等
- 包括基于HTML/AJAX的配置器应用程序,用于实时测试和配置
- 具有命令行工具,便于使用
- 易于与现代框架(如Symfony)集成
要求
- PHP 7.2.5+ 或 PHP 8.0+
- Composer - https://getcomposer.org/
动作示例
需要处理的示例文本数据
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; }
插件和工作器内的辅助工具
您可以使用由 AbstractPlugin
和 AbstractWorker
抽象类提供的某些包含的辅助工具。当您从它们扩展类时,您将有权访问一些有用的方法
$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
变更日志
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