tarsana / syntax
一个基于灵活和可组合的语法定义进行字符串编码和解码的工具。
Requires
- php: ^7.0
Requires (Dev)
- phpunit/phpunit: ^6.1
This package is auto-updated.
Last update: 2024-09-21 11:06:18 UTC
README
一个基于灵活和可组合的语法定义进行字符串编码和解码的工具。
目录
快速示例
警告:这只是个预告,如果代码看起来有点复杂,请不要担心,在阅读了逐步指南后您就会理解。
假设您有以下代表开发者列表的文本,其中每行都遵循以下语法
first-name last-name [number-of-followers] [repo-name:stars,repo-name:stars,...]
Tammy Flores 257 library:98,fast-remote:5,anyway:987
Rebecca Welch forever:76,oops:0
Walter Phillips 423
语法可以帮助您轻松解析此文档并将其转换为可操作的对象。
让我们试试看
<?php require __DIR__ . '/../vendor/autoload.php'; use Tarsana\Syntax\Factory as S; // a repo is an object having a name (string) and stars (number), separated by ':' $repo = "{name: string, stars:number}"; // a line consists of a first and last names, optional number of followers, and repos, separated by space. The repos are separated by "," $line = "{first_name, last_name, followers: (number: 0), repos: ([{$repo}]:[]) | }"; // a document is a list of lines separated by PHP_EOL $document = "[{$line}|".PHP_EOL."]"; // Now we make the syntax object $documentSyntax = S::syntax()->parse($document); // Then we can use the defined syntax to parse the document: $developers = $documentSyntax->parse(trim(file_get_contents(__DIR__ . '/files/devs.txt')));
$developers
将包含以下内容
[ { "first_name": "Tammy", "last_name": "Flores", "followers": 257, "repos": [ { "name": "library", "stars": 98 }, { "name": "fast-remote", "stars": 5 }, { "name": "anyway", "stars": 987 } ] }, { "first_name": "Rebecca", "last_name": "Welch", "followers": "", "repos": [ { "name": "forever", "stars": 76 }, { "name": "oops", "stars": 0 } ] }, { "first_name": "Walter", "last_name": "Phillips", "followers": 423, "repos": "" } ]
您修改了$developers
并希望以相同的语法将其保存回文档?您可以这样操作
// ... manipulating $developers file_put_contents('path/to/file', $documentSyntax->dump($developers));
安装
使用composer进行安装
composer require tarsana/syntax
逐步指南
类Tarsana\Syntax\Factory
提供了一些有用的静态方法来创建语法。在本指南中,我们将从基础知识开始,然后展示如何使用SyntaxSyntax
来更快地完成工作。
解析和导出字符串
<?php use Tarsana\Syntax\Factory as S; $string = S::string(); // instance of Tarsana\Syntax\StringSyntax $string->parse('Lorem ipsum dolor sit amet'); //=> 'Lorem ipsum dolor sit amet' $string->parse(''); // Tarsana\Syntax\Exceptions\ParseException: Error while parsing '' as String at character 0: String should not be empty $string->dump('Lorem ipsum dolor sit amet'); //=> 'Lorem ipsum dolor sit amet' $string->dump(''); //=> ''
解析和导出数字
<?php use Tarsana\Syntax\Factory as S; $number = S::number(); // instance of Tarsana\Syntax\NumberSyntax $number->parse('58.9'); //=> 58.9 $number->parse('Lorem12'); // Tarsana\Syntax\Exceptions\ParseException: Error while parsing 'Lorem' as Number at character 0: Not a numeric value
解析和导出布尔值
<?php use Tarsana\Syntax\Factory as S; $boolean = S::boolean(); // instance of Tarsana\Syntax\BooleanSyntax $boolean->parse('true'); //=> true $boolean->parse('yes'); //=> true $boolean->parse('y'); //=> true $boolean->parse('TrUe'); //=> true (case insensitive) $boolean->parse('false'); //=> false $boolean->parse('no'); //=> false $boolean->parse('N'); //=> false $boolean->parse('Lorem'); // Tarsana\Syntax\Exceptions\ParseException: Error while parsing 'Lorem' as Boolean at character 0: Boolean value should be one of "yes", "no", "y", "n", "true", "false" $boolean->dump(true); //=> 'true' $boolean->dump(false); //=> 'false' $boolean->dump('Lorem'); // Tarsana\Syntax\Exceptions\DumpException: Error while dumping some input as Boolean: Not a boolean
解析和导出数组
Tarsana\Syntax\ArraySyntax
表示具有相同语法并由相同字符串分隔的元素数组。因此,ArraySyntax
是使用一个Syntax
(可能是NumberSyntax
、StringSyntax
或任何其他)和一个separator
构建的。
-
如果省略了
Syntax
参数,则默认使用StringSyntax
实例。 -
如果省略了
separator
参数,则默认使用','
。
<?php use Tarsana\Syntax\Factory as S; $strings = S::array(); $strings->parse('aa:bb,cc,"ss,089",true'); //=> ['aa:bb','cc','ss,089','true'] // Note that we can use "..." to escape the separator $strings->dump(['aa','bb,cc','76']); //=> 'aa,"bb,cc",76' // Yeah, it's smart enough to auto-escape items containing the separator $vector = S::array(S::number()); $vector->parse('1,2,3,4,5'); //=> [1, 2, 3, 4, 5] $matrix = S::array($vector, PHP_EOL); $matrix->parse( '1,2,3 4,5,6,7 8,9,100'); //=> [ [1, 2, 3], [4, 5, 6, 7], [8, 9, 100] ]
解析和导出可选语法
Tarsana\Syntax\Optional
表示一个可选语法。给定一个语法和静态默认值;它将尝试使用该语法解析输入,并在失败时返回默认值。
<?php use Tarsana\Syntax\Factory as S; $optionalNumber = S::optional(S::number(), 10); $optionalNumber->parse(15); //=> 15 $optionalNumber->success(); //=> true $optionalNumber->parse('Yo'); //=> 10 (the default value) $optionalNumber->success(); //=> false
解析和导出对象
Tarsana\Syntax\ObjectSyntax
表示一个对象,其中每个字段都可以有自己的语法。它通过提供字段关联数组和separator
(如果缺失,则默认为':'
)来定义。
<?php use Tarsana\Syntax\Factory as S; $repository = S::object([ 'name' => S::string(), 'is_private' => S::optional(S::boolean(), false), 'forks' => S::optional(S::number(), 0), 'stars' => S::optional(S::number(), 0) ]); $repository->parse('tarsana/syntax'); // an stdClass as below // { // name: 'tarsana/syntax', // is_private: false, // forks: 0, // stars: 0 // } $repository->parse('tarsana/syntax:5'); // { // name: 'tarsana/syntax', // is_private: false, // forks: 5, // stars: 0 // } $repository->parse('tarsana/syntax:yes:7'); // { // name: 'tarsana/syntax', // is_private: true, // forks: 7, // stars: 0 // } $data = (object) [ 'name' => 'foo/bar', 'is_private' => false, 'forks' => 9, 'stars' => 3 ]; $repository->dump($data); // 'foo/bar:false:9:3' $developer = S::object([ 'name' => S::string(), 'followers' => S::optional(S::number(), 0), 'repositories' => S::optional(S::array($repository), []) ], ' '); $developer->parse('Amine'); // { // name: 'Amine', // followers: 0, // repositories: [] // } $developer->parse('Amine tarsana/syntax,webNeat/lumen-generators:16:57'); // { // name: 'Amine', // followers: 0, // repositories: [ // { name: 'tarsana/syntax', is_private: false, forks: 0, stars: 0 }, // { name: 'webNeat/lumen-generators', is_private: false, forks: 16, stars: 57 } // ] // }
解析和导出语法
现在您已经知道如何解析和导出基本类型:string
、boolean
、number
、array
、optional
和object
。但您可能会注意到,编写复杂语法(包括数组、对象等)的代码需要很多复杂的行。为此,引入了SyntaxSyntax
来解决这个问题。正如其名所示,它是一个解析和导出语法的Syntax
,一个元语法!
因此,您不必编写以下内容
$personSyntax = S::object([ 'name' => S::string(), 'age' => S::number(), 'vip' => S::boolean(), 'friends' => S::array() ]);
您只需编写以下内容
$personSyntax = S::syntax()->parse('{name, age:number, vip:boolean, friends:[]}');
规则
S::string()
是string
。S::number()
是number
。S::boolean()
是boolean
。S::syntax()
是syntax
。S::optional($type, $default)
是(type:default)
,其中type
是$type
对应的字符串,而default
是json_encode($default)
。S::array($type, $separator)
是[type|separator]
,其中type
是与$type
对应的字符串,而separator
与$separator
相同。如果省略分隔符(即[type]
),则默认值为,
。S::object(['name1' => $type1, 'name2' => $type2], $separator)
是{name1:type1, name2:type2 |separator}
。如果省略分隔符,则默认值为:
。
示例
// '{name: string, age: number}' S::object([ 'name' => S::string(), 'age' => S::number() ]) // '{position: {x: number, y: number |"|"}, width:number, height:number}' S::obejct([ 'position' => S::object([ 'x' => S::number(), 'y' => S::number() ], '|'), 'width' => S::number(), 'height' => S::number() ]) // '{name, stars:number, contributers: [{name, email|-}]}' S::object([ 'name' => S::string(), 'stars' => S::number(), 'contributers' => S::array(S::object([ 'name' => S::string(), 'email' => S::string() ], '-')) ])
开发笔记及下一步计划
-
版本 2.1.0
语法
已添加到字符串表示形式中,并对应于S::syntax()
实例。
-
版本 2.0.0
- 在从字符串创建语法时,可以指定分隔符和默认值。
- 现在可以转义分隔符。
- 添加了
OptionalSyntax
。 - 从
Syntax
类中移除了属性default
和description
。 - 升级到 PHPUnit 6 和 PHP 7。
- 无依赖。
- 详细的异常,包含错误位置。
- 更好的
Factory
方法。
-
版本 1.2.1:
-
tarsana/functional
依赖项更新 -
修复了一些错误。
-
-
版本 1.2.0:
-
添加了
SyntaxSyntax
。 -
向
ArraySyntax
添加了separator
和itemSyntax
的获取器和设置器。 -
向
ObjectSyntax
添加了separator
和fields
的获取器和设置器。
-
-
版本 1.1.0:
- 向
Syntax
添加了description
属性以存储额外的详细信息。
- 向
-
版本 1.0.1:
-
测试覆盖率现在为 100%
-
修复了
ArraySyntax
和ObjectSyntax
的一些小错误。
-
-
版本 1.0.0:String、Number、Boolean、Array 和 Object 语法。
贡献
请在修复或创建语法之前查看代码,了解其他语法类的实现和测试方式。欢迎所有反馈和拉取请求 :D