tarsana/syntax

一个基于灵活和可组合的语法定义进行字符串编码和解码的工具。

2.1.0 2017-09-08 04:27 UTC

This package is auto-updated.

Last update: 2024-09-21 11:06:18 UTC


README

Build Status Coverage Status SensioLabsInsight Software License

一个基于灵活和可组合的语法定义进行字符串编码和解码的工具。

目录

快速示例

警告:这只是个预告,如果代码看起来有点复杂,请不要担心,在阅读了逐步指南后您就会理解。

假设您有以下代表开发者列表的文本,其中每行都遵循以下语法

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(可能是NumberSyntaxStringSyntax或任何其他)和一个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 }
//  ]
// }

解析和导出语法

现在您已经知道如何解析和导出基本类型:stringbooleannumberarrayoptionalobject。但您可能会注意到,编写复杂语法(包括数组、对象等)的代码需要很多复杂的行。为此,引入了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对应的字符串,而defaultjson_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 类中移除了属性 defaultdescription
    • 升级到 PHPUnit 6 和 PHP 7。
    • 无依赖。
    • 详细的异常,包含错误位置。
    • 更好的 Factory 方法。
  • 版本 1.2.1:

    • tarsana/functional 依赖项更新

    • 修复了一些错误。

  • 版本 1.2.0:

    • 添加了 SyntaxSyntax

    • ArraySyntax 添加了 separatoritemSyntax 的获取器和设置器。

    • ObjectSyntax 添加了 separatorfields 的获取器和设置器。

  • 版本 1.1.0:

    • Syntax 添加了 description 属性以存储额外的详细信息。
  • 版本 1.0.1:

    • 测试覆盖率现在为 100%

    • 修复了 ArraySyntaxObjectSyntax 的一些小错误。

  • 版本 1.0.0:String、Number、Boolean、Array 和 Object 语法。

贡献

请在修复或创建语法之前查看代码,了解其他语法类的实现和测试方式。欢迎所有反馈和拉取请求 :D