优化跳过性能

This commit is contained in:
Jerry Yan 2020-12-19 15:17:13 +08:00
parent 4c4be41f8b
commit 89470252e7
3 changed files with 100 additions and 44 deletions

View File

@ -47,22 +47,18 @@ abstract class ReaderInterface
*/ */
abstract public function moveToNextToken(): bool; abstract public function moveToNextToken(): bool;
/** abstract protected function getBetween(int $start = 0, int $end = 0): string;
* 跳过当前行
* @return bool
* @author Jerry Yan <792602257@qq.com>
* @date 2020/12/17 15:43
*/
abstract public function skipCurrentLine(): bool;
/** /**
* 从当前位置跳到结束位置 * 从当前位置跳到结束位置
* @param string $end * @param string[] $chars
* @return bool * @param int|null $startAt
* @param string $matched
* @return int|null
* @author Jerry Yan <792602257@qq.com> * @author Jerry Yan <792602257@qq.com>
* @date 2020/12/17 15:43 * @date 2020/12/17 15:43
*/ */
abstract public function skipUntil(string $end = "*/"): bool; abstract public function findNextChars(array $chars, int $startAt = null, string &$matched = ""): ?int;
/** /**
* 重置读取器 * 重置读取器
@ -113,15 +109,84 @@ abstract class ReaderInterface
return $this->currentToken; return $this->currentToken;
} }
protected function moveCursorToNextChar(): void /**
* 跳过当前行
* @return bool
* @author Jerry Yan <792602257@qq.com>
* @date 2020/12/17 15:43
*/
public function skipCurrentLine(): bool
{ {
$this->currentPosition++; $_ = $this->moveCursorToNextLine();
if ($_ === false) return false;
return $this->moveToNextToken();
} }
protected function moveCursorToNextLine(int $chars = 1): void /**
* 移动Cursor至下一字符
* @param int $charLength
* @author Jerry Yan <792602257@qq.com>
* @date 2020/12/19 15:05
*/
protected function moveCursorToNextChar(int $charLength = 1): void
{ {
$this->currentPosition += $chars; $this->currentPosition += $charLength;
}
/**
* 移动Cursor至下一行
* @param int|null $newPos 下一行位置,不提供则手动检测
* @return bool
* @author Jerry Yan <792602257@qq.com>
* @date 2020/12/19 15:05
*/
protected function moveCursorToNextLine(int $newPos = null): bool
{
if ($newPos === null) {
$curPos = $this->currentPosition;
$newPos = $this->findNextChars(["\r\n", "\r", "\n"], $curPos);
if ($newPos === null) return false;
$this->nextPosition = $newPos;
}
$this->moveCursorToNextChar($newPos - $this->currentPosition);
$this->currentLineDelta = $this->currentPosition; $this->currentLineDelta = $this->currentPosition;
$this->currentLine++; $this->currentLine++;
return true;
} }
/**
* Cursor向后移动多少字符
* @param int $length 字符长度
* @return bool 是否成功
* @author Jerry Yan <792602257@qq.com>
* @date 2020/12/19 15:13
*/
protected function moveCursorAfter(int $length): bool
{
$lastLinePos = $pos = $this->currentPosition;
$end = $pos + $length;
while ($pos < $end) {
$pos = $this->findNextChars(["\r\n", "\r", "\n"], $pos);
if ($pos === null || $pos > $end) break;
$this->moveCursorToNextLine($pos);
$lastLinePos = $pos;
}
$this->moveCursorToNextChar($end - $lastLinePos);
return true;
}
/**
* 移动到新的位置
* @param int $newPos
* @return bool
* @author Jerry Yan <792602257@qq.com>
* @date 2020/12/19 15:14
*/
protected function moveCursorTo(int $newPos): bool
{
// TODO: Forward Or Backward
$this->moveCursorAfter($newPos - $this->currentPosition);
return false;
}
} }

View File

@ -112,33 +112,24 @@ class StringReader extends ReaderInterface
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function skipCurrentLine(): bool public function findNextChars(array $chars, int $startAt = null, string &$matched = ""): ?int
{ {
$curPos = $this->currentPosition; if (empty($chars)) return null;
while ($curChar = $this->getNextChar($curPos)) { if ($startAt === null) $startAt = $this->currentPosition;
$curPos++; /** @var array<string, int> $result */
switch ($curChar) { $result = [];
case "\r": foreach ($chars as $char) {
if ($this->getNextChar($curPos) === "\n") { $_ = mb_strpos($this->string, $char, $startAt);
// CRLF换行 if ($_ !== false) $result[$char] = $_;
$curPos++;
} }
break 2; if (empty($result)) return null;
case "\n": asort($result);
break 2; $matched = array_keys($result)[0];
} return $result[$matched] + mb_strlen($matched);
}
$this->nextPosition = $curPos;
$this->moveCursorToNextLine($curPos - $this->currentPosition);
return $this->moveToNextToken();
} }
/** protected function getBetween(int $start = 0, int $end = 0): string
* @inheritDoc
*/
public function skipUntil(string $end = "*/"): bool
{ {
// TODO: Implement skipUntil() method. return mb_substr($this->string, $start, $end - $start);
return true;
} }
} }

View File

@ -29,13 +29,13 @@ class StringReaderTest extends TestCase
'moveToNextLines' => [], 'moveToNextLines' => [],
]; ];
$this->thingsWithCrLf = [ $this->thingsWithCrLf = [
'original' => " 中文 \r\n\r 这是 \r Is \n\n 一个 新的 TOken", 'original' => " 中文 \r\n\r 这是 \r Is A \n\n 一个 新的 TOken",
'tokens' => ["中文", "这是", "Is", "一个", "新的", "TOken"], 'tokens' => ["中文", "这是", "Is", "A", "一个", "新的", "TOken"],
'nextTokens' => ["这是", "Is", "一个", "新的", "TOken", ""], 'nextTokens' => ["这是", "Is", "A", "一个", "新的", "TOken", ""],
'positions' => [1, 8, 13, 19, 22, 25], 'positions' => [1, 8, 13, 16, 21, 24, 27],
'lines' => [1, 3, 4, 6, 6, 6], 'lines' => [1, 3, 4, 4, 6, 6, 6],
'linePositions' => [1, 1, 1, 1, 4, 7], 'linePositions' => [1, 1, 1, 4, 1, 4, 7],
'moveToNextLines' => [1, 2, 3], 'moveToNextLines' => [1, 2, 4],
]; ];
$this->reader = new StringReader($this->things['original']); $this->reader = new StringReader($this->things['original']);
$this->readerWithCrLf = new StringReader($this->thingsWithCrLf['original']); $this->readerWithCrLf = new StringReader($this->thingsWithCrLf['original']);