From 89470252e79e190ee80a53ed9d236689d312e491 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Sat, 19 Dec 2020 15:17:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=B7=B3=E8=BF=87=E6=80=A7?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Reader/ReaderInterface.php | 93 ++++++++++++++++++++++++++----- src/Reader/StringReader.php | 37 +++++------- tests/Reader/StringReaderTest.php | 14 ++--- 3 files changed, 100 insertions(+), 44 deletions(-) diff --git a/src/Reader/ReaderInterface.php b/src/Reader/ReaderInterface.php index 224b805..f4d2c19 100644 --- a/src/Reader/ReaderInterface.php +++ b/src/Reader/ReaderInterface.php @@ -47,22 +47,18 @@ abstract class ReaderInterface */ abstract public function moveToNextToken(): bool; - /** - * 跳过当前行 - * @return bool - * @author Jerry Yan <792602257@qq.com> - * @date 2020/12/17 15:43 - */ - abstract public function skipCurrentLine(): bool; + abstract protected function getBetween(int $start = 0, int $end = 0): string; /** * 从当前位置跳到结束位置 - * @param string $end - * @return bool + * @param string[] $chars + * @param int|null $startAt + * @param string $matched + * @return int|null * @author Jerry Yan <792602257@qq.com> * @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; } - 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->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; + } + } \ No newline at end of file diff --git a/src/Reader/StringReader.php b/src/Reader/StringReader.php index aedafaa..a4bb497 100644 --- a/src/Reader/StringReader.php +++ b/src/Reader/StringReader.php @@ -112,33 +112,24 @@ class StringReader extends ReaderInterface /** * @inheritDoc */ - public function skipCurrentLine(): bool + public function findNextChars(array $chars, int $startAt = null, string &$matched = ""): ?int { - $curPos = $this->currentPosition; - while ($curChar = $this->getNextChar($curPos)) { - $curPos++; - switch ($curChar) { - case "\r": - if ($this->getNextChar($curPos) === "\n") { - // CRLF换行 - $curPos++; - } - break 2; - case "\n": - break 2; - } + if (empty($chars)) return null; + if ($startAt === null) $startAt = $this->currentPosition; + /** @var array $result */ + $result = []; + foreach ($chars as $char) { + $_ = mb_strpos($this->string, $char, $startAt); + if ($_ !== false) $result[$char] = $_; } - $this->nextPosition = $curPos; - $this->moveCursorToNextLine($curPos - $this->currentPosition); - return $this->moveToNextToken(); + if (empty($result)) return null; + asort($result); + $matched = array_keys($result)[0]; + return $result[$matched] + mb_strlen($matched); } - /** - * @inheritDoc - */ - public function skipUntil(string $end = "*/"): bool + protected function getBetween(int $start = 0, int $end = 0): string { - // TODO: Implement skipUntil() method. - return true; + return mb_substr($this->string, $start, $end - $start); } } \ No newline at end of file diff --git a/tests/Reader/StringReaderTest.php b/tests/Reader/StringReaderTest.php index e7faf2a..2cbc18a 100644 --- a/tests/Reader/StringReaderTest.php +++ b/tests/Reader/StringReaderTest.php @@ -29,13 +29,13 @@ class StringReaderTest extends TestCase 'moveToNextLines' => [], ]; $this->thingsWithCrLf = [ - 'original' => " 中文 \r\n\r 这是 \r Is \n\n 一个 新的 TOken", - 'tokens' => ["中文", "这是", "Is", "一个", "新的", "TOken"], - 'nextTokens' => ["这是", "Is", "一个", "新的", "TOken", ""], - 'positions' => [1, 8, 13, 19, 22, 25], - 'lines' => [1, 3, 4, 6, 6, 6], - 'linePositions' => [1, 1, 1, 1, 4, 7], - 'moveToNextLines' => [1, 2, 3], + 'original' => " 中文 \r\n\r 这是 \r Is A \n\n 一个 新的 TOken", + 'tokens' => ["中文", "这是", "Is", "A", "一个", "新的", "TOken"], + 'nextTokens' => ["这是", "Is", "A", "一个", "新的", "TOken", ""], + 'positions' => [1, 8, 13, 16, 21, 24, 27], + 'lines' => [1, 3, 4, 4, 6, 6, 6], + 'linePositions' => [1, 1, 1, 4, 1, 4, 7], + 'moveToNextLines' => [1, 2, 4], ]; $this->reader = new StringReader($this->things['original']); $this->readerWithCrLf = new StringReader($this->thingsWithCrLf['original']);