Tokenstream有什么用?Tokenstream价值深度解读!

吉云

今天跟大家聊聊我最近在做的 tokenstream 实践,一开始看到这个东西,我也是一头雾水,不知道是干嘛的。但是没办法,工作需要,硬着头皮开始啃。

我得明确 tokenstream 是个从字面意思理解,就是“令牌流”。更具体点,它就是一个包含各种分词信息的流,可以有效地获取分词单元。想象一下,你有一段文字,比如 "今天天气真好",经过分词器处理后,会变成 "今天"、"天气"、"真好" 这样的一个个词语,而 tokenstream 就是用来存放这些词语信息的。

我最开始是从一个开源库 phpunit/php-token-stream 入手的,这个库挺有意思,是 PHPUnit 的开发者写的,可以用来处理 PHP 代码的 token。我先是把这个库 down 下来,然后仔仔细细的看它的源码。代码量不大,但是逻辑还是挺绕的。

Tokenstream有什么用?Tokenstream价值深度解读!

我就开始动手写代码。我的目标是实现一个简单的 tokenstream,能够把一段字符串分割成一个个 token。我先定义一个 Token 类,用来表示一个 token,包含 token 的类型、值、起始位置和结束位置等信息。

php

class Token {

public $type;

public $value;

public $start;

Tokenstream有什么用?Tokenstream价值深度解读!

public $end;

然后,我写一个Tokenizer类,用来做分词。这个类主要负责接收字符流,然后根据一定的规则,将字符流分割成一个个 token。我这里用的是最简单的空格分割:

php

class Tokenizer {

Tokenstream有什么用?Tokenstream价值深度解读!

private $input;

private $position;

public function __construct($input) {

$this->input = $input;

$this->position = 0;

Tokenstream有什么用?Tokenstream价值深度解读!

public function nextToken() {

if ($this->position >= strlen($this->input)) {

return null;

$start = $this->position;

while ($this->position < strlen($this->input) && $this->input[$this->position] != ' ') {

Tokenstream有什么用?Tokenstream价值深度解读!

$this->position++;

$value = substr($this->input, $start, $this->position - $start);

$token = new Token();

$token->type = 'word';

$token->value = $value;

Tokenstream有什么用?Tokenstream价值深度解读!

$token->start = $start;

$token->end = $this->position;

if ($this->position < strlen($this->input)) {

$this->position++; // Skip the space

return $token;

Tokenstream有什么用?Tokenstream价值深度解读!

有Tokenizer,接下来就是实现TokenStream。TokenStream 负责存储和遍历 Tokenizer 生成的 token。它需要实现一个 `nextToken` 方法,用来获取下一个 token。

php

class TokenStream {

Tokenstream有什么用?Tokenstream价值深度解读!

private $tokenizer;

private $currentToken;

public function __construct($input) {

$this->tokenizer = new Tokenizer($input);

$this->currentToken = $this->tokenizer->nextToken();

Tokenstream有什么用?Tokenstream价值深度解读!

public function nextToken() {

$token = $this->currentToken;

$this->currentToken = $this->tokenizer->nextToken();

return $token;

public function peek() {

Tokenstream有什么用?Tokenstream价值深度解读!

return $this->currentToken;

我写一个简单的测试用例,验证一下我的 tokenstream 是否能够正常工作:

php

Tokenstream有什么用?Tokenstream价值深度解读!

$input = "This is a test string";

$tokenStream = new TokenStream($input);

while ($token = $tokenStream->nextToken()) {

echo "Type: " . $token->type . ", Value: " . $token->value . ", Start: " . $token->start . ", End: " . $token->end . "\n";

Tokenstream有什么用?Tokenstream价值深度解读!

跑一下测试,结果还不错,能够正确地将字符串分割成一个个 token,并输出 token 的信息。

我这个 tokenstream 还非常简单,只能处理空格分割的字符串。如果想要处理更复杂的文本,比如包含标点符号、数字、特殊字符等等,就需要对 Tokenizer 进行更复杂的处理。而且还可以加入 Token Filter,对 token 进行过滤,比如转换为小写、去除停用词等等。

这回实践让我对 tokenstream 有一个更深入的解。虽然实现过程比较 rough,但是也让我体会到 tokenstream 的基本原理和作用。以后有机会,我会继续深入研究,争取做一个更完善的 tokenstream。

免责声明:由于无法甄别是否为投稿用户创作以及文章的准确性,本站尊重并保护知识产权,根据《信息网络传播权保护条例》,如我们转载的作品侵犯了您的权利,请您通知我们,请将本侵权页面网址发送邮件到qingge@88.com,深感抱歉,我们会做删除处理。

目录[+]