phug / reader
Pug (前身为Jade) 的 PHP 字符串读取器,基于缩进来构建的 HTML 模板引擎
Requires
- php: >=5.5.0
- phug/util: ^0.3.5 || ^1.0
- psr/http-message: ^1.0
- symfony/polyfill-mbstring: *
- dev-master / 1.x-dev
- 1.13.0
- 1.12.3
- 1.12.2
- 1.12.1
- 1.12.0
- 1.11.0
- 1.10.0
- 1.9.0
- 1.8.3
- 1.8.2
- 1.8.1
- 1.8.0
- 1.7.3
- 1.7.2
- 1.7.1
- 1.7.0
- 1.6.0
- 1.5.0
- 1.4.0
- 1.4.0-beta2
- 1.4.0-beta1
- 1.3.0
- 1.2.0
- 1.1.0
- 1.0.1
- 1.0.0
- 1.0.0-RC3
- 1.0.0-RC.2
- 1.0.0-rc.1
- 0.2.2
- 0.2.1
- 0.2.0
- 0.1.4
- 0.1.3
- 0.1.2
- 0.1.1
- 0.1.0
- dev-analysis-xgmrM9
- dev-feature/abstract-token-handler
- dev-feature/duplication-threshold
- dev-feature/multi-tester-3
- dev-feature/symfony-7
- dev-fix/strict-in-array
- dev-remotes/pull/100/merge
- dev-remotes/pull/101/merge
- dev-remotes/pull/102/merge
- dev-remotes/pull/104/merge
- dev-remotes/pull/105/merge
- dev-remotes/pull/106/merge
- dev-remotes/pull/107/merge
- dev-remotes/pull/108/merge
- dev-remotes/pull/109/merge
- dev-remotes/pull/110/merge
- dev-remotes/pull/111/merge
- dev-remotes/pull/113/merge
- dev-remotes/pull/114/merge
- dev-remotes/pull/98/merge
- dev-remotes/pull/99/merge
- dev-simplify-split-script
- dev-multitest-php-8
- dev-feature/check-php-8
- dev-feature/issue-69-interpolations-in-comments
- dev-feature/issue-70-disallow-new-line-in-interpolations
- dev-feature/php-8-namespace
This package is auto-updated.
Last update: 2024-09-19 15:53:11 UTC
README
什么是 Phug Reader?
Reader 类是一个小型实用工具,可以解析和扫描字符串以查找特定实体。
它主要基于正则表达式,但也引入了扫描任何类型字符串和表达式的工具(例如字符串转义、括号计数等)
传递给 Reader 的字符串将通过 consume
机制逐字节吞咽。当字符串为空时,通常完成解析。
这个类专门用于词法分析和表达式验证。
安装
通过 Composer 安装
composer require phug/reader
用法
基础
使用 Phug\Reader
读取的过程涉及 查看 和 消费。你 查看,检查它是否是你想要的,如果是,你就 消费。
Reader 上的 read-方法将自动查看和消费,直到找到你搜索的内容。 match-方法类似于 peek,但使用正则表达式。
让我们创建一个小的示例代码来解析
$code = 'someString = "some string"';
现在我们为这段代码创建一个 Reader
$reader = new Reader($code);
如果你需要一个固定的编码,请使用第二个 $encoding
参数。
现在我们可以开始读取过程。首先,我们想要读取我们的标识符。我们可以通过使用 readIdentifier()
来轻松完成,如果未遇到标识符,则返回 null
,否则返回找到的标识符。它会在遇到任何不是标识符字符的任何内容时停止(在这种情况下标识符后的空格)
$identifier = $reader->readIdentifier(); if ($identifier === null) { throw new Exception("Failed to read: Identifier expected"); } var_dump($identifier); //`someString`
要直接到达我们的 =
字符,我们只需跳过我们遇到的任何空格。这也允许你使用任何你想要的间距(例如,如果你喜欢,你可以用制表符缩进上面的代码)
$reader->readSpaces();
如果我们需要空格,我们总是可以捕获返回的结果。如果没有遇到空格,它将只返回 null
。
现在我们想要解析赋值运算符(=
)(或者更确切地说,验证它是否存在)
if (!$reader->peekChar('=')) { throw new Exception("Failed to read: Assignment expected"); } //Consume the result, since we're `peek`ing, not `read`ing. $reader->consume();
再次跳过空格
$reader->readSpaces();
然后读取字符串。如果没有遇到引号字符("
或 '
),则返回 null
。否则,它将返回(已解析的)字符串,不带引号。请注意,你必须明确检查 null
,因为我们也可能有一个空字符串(""
),它在 PHP 中求值为 true
。
$string = $reader->readString(); if ($string === null) { throw new Exception("Failed to read: Expected string"); } var_dump($string); //`some string`
默认情况下,遇到的引号样式将被转义,这样你就可以正确地扫描 "some \" string"
。如果你想添加其他转义,请使用 readString
的第一个参数。
现在你已经有了解析的所有部分,可以组成你的实际动作
echo "Set `$identifier` to `$string`"; //Set `someString` to `some string`
并且已经以这种方式进行了验证。
这只是一个小的示例,Phug Reader 是为了循环解析而设计的。
构建一个小型的分词器
use Phug\Reader; //Some C-style example code $code = 'someVar = {a, "this is a string (really, it \"is\")", func(b, c), d}'; $reader = new Reader($code); $tokens = []; $blockLevel = 0; $expressionLevel = 0; while ($reader->hasLength()) { //Skip spaces of any kind. $reader->readSpaces(); //Scan for identifiers if ($identifier = $reader->readIdentifier()) { $tokens[] = ['type' => 'identifier', 'name' => $identifier]; continue; } //Scan for Assignments if ($reader->peekChar('=')) { $reader->consume(); $tokens[] = ['type' => 'assignment']; continue; } //Scan for strings if (($string = $reader->readString()) !== null) { $tokens[] = ['type' => 'string', 'value' => $string]; continue; } //Scan block start if ($reader->peekChar('{')) { $reader->consume(); $blockLevel++; $tokens[] = ['type' => 'blockStart']; continue; } //Scan block end if ($reader->peekChar('}')) { $reader->consume(); $blockLevel--; $tokens[] = ['type' => 'blockEnd']; continue; } //Scan parenthesis start if ($reader->peekChar('(')) { $reader->consume(); $expressionLevel++; $tokens[] = ['type' => 'listStart']; continue; } //Scan parenthesis end if ($reader->peekChar(')')) { $reader->consume(); $expressionLevel--; $tokens[] = ['type' => 'listEnd']; continue; } //Scan comma if ($reader->peekChar(',')) { $reader->consume(); $tokens[] = ['type' => 'next']; continue; } throw new \Exception( "Unexpected ".$reader->peek(10) ); } if ($blockLevel || $expressionLevel) throw new \Exception("Unclosed bracket encountered"); var_dump($tokens); /* Output: [ ['type' => 'identifier', 'name' => 'someVar'], ['type' => 'assignment'], ['type' => 'blockStart'], ['type' => 'identifier', 'name' => 'a'], ['type' => 'next'], ['type' => 'string', 'value' => 'this is a string (really, it "is")'], ['type' => 'next'], ['type' => 'identifier', 'name' => 'func'], ['type' => 'listStart'], ['type' => 'identifier', 'name' => 'b'], ['type' => 'next'], ['type' => 'identifier', 'name' => 'c'], ['type' => 'listEnd'], ['type' => 'next'], ['type' => 'identifier', 'name' => 'd'], ['type' => 'blockEnd'] ] */
保持表达式完整
有时你想要保持表达式完整,例如,当你允许包含需要单独解析的第三方代码时。
Reader 提供了一个括号计数实用工具,可以做到这一点。让我们以 Jade
为例
a(href=getUri('/abc', true), title=(title ? title : 'Sorry, no title.'))
为了解析这个,我们来做以下操作
//Scan Identifier ("a") $identifier = $reader->readIdentifier(); $attributes = []; //Enter an attribute block if available if ($reader->peekChar('(')) { $reader->consume(); while ($reader->hasLength()) { //Ignore spaces $reader->readSpaces(); //Scan the attribute name if (!($name = $this->readIdentifier())) { throw new \Exception("Attributes need a name!"); } //Ignore spaces $reader->readSpaces(); //Make sure there's a =-character if (!$reader->peekChar('=')) { throw new \Exception("Failed to read: Expected attribute value"); } $reader->consume(); //Ignore spaces $reader->readSpaces(); //Read the expression until , or ) is encountered //It will ignore , and ) inside any kind of brackets and count brackets correctly until we actually //reached the end-bracket $value = $reader->readExpression([',', ')']); //Add the attribute to our attribute array $attributes[$name] = $value; //If we don't encounter a , to go on, we break the loop if (!$reader->peekChar(',')) { break; } //Else we consume the , and continue our attribute parsing $reader->consume(); } //Now make sure we actually closed our attribute block correctly. if (!$reader->peekChar(')')) { throw new \Exception("Failed to read: Expected closing bracket"); } } $element = ['identifier' => $identifier, 'attributes' => $attributes]; var_dump($element); /* Output: [ 'identifier' => 'a', 'attributes' => [ 'href' => 'getUri(\'/abc\', true)', 'title' => '(title ? title : \'Sorry, no title.\')' ] ] */
现在你已经有了一个用于(非常基础的)Jade元素的解析器!它可以处理你喜欢的任意数量的属性,以及所有你能想到的可能值,而不会打断列表,无论包含多少逗号和括号。
深入研究,Phug Reader实际上能够解析任何类型的源代码和文本。