From f995b932e47e84662d57ea8ac0b31f1c2ebb7c8d Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Sat, 19 Dec 2020 11:41:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=85=89=E6=A0=87=E7=A7=BB?= =?UTF-8?q?=E5=8A=A8=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Reader/ReaderInterface.php | 27 +++++++++++++++++++- src/Reader/StringReader.php | 27 +++++++++++++------- tests/Reader/StringReaderTest.php | 42 +++++++++++++++++++++++++++++-- 3 files changed, 84 insertions(+), 12 deletions(-) diff --git a/src/Reader/ReaderInterface.php b/src/Reader/ReaderInterface.php index c668710..3570aa5 100644 --- a/src/Reader/ReaderInterface.php +++ b/src/Reader/ReaderInterface.php @@ -62,7 +62,7 @@ abstract class ReaderInterface * @author Jerry Yan <792602257@qq.com> * @date 2020/12/17 15:43 */ - abstract public function skipUntil(string $end="*/"): bool; + abstract public function skipUntil(string $end = "*/"): bool; /** * 重置读取器 @@ -91,12 +91,37 @@ abstract class ReaderInterface { return $this->currentPosition; } + public function getNextPosition(): int { return $this->nextPosition; } + + public function getCurrentLine(): int + { + return $this->currentLine; + } + + public function getCurrentLinePosition(): int + { + return $this->currentLinePosition; + } + public function getCurrentToken(): string { return $this->currentToken; } + + protected function moveCursorToNextChar(): void + { + $this->currentPosition++; + $this->currentLinePosition++; + } + + protected function moveCursorToNextLine(int $chars = 1): void + { + $this->currentPosition += $chars; + $this->currentLinePosition = 0; + $this->currentLine++; + } } \ No newline at end of file diff --git a/src/Reader/StringReader.php b/src/Reader/StringReader.php index 075f7ea..2b918c8 100644 --- a/src/Reader/StringReader.php +++ b/src/Reader/StringReader.php @@ -47,6 +47,9 @@ class StringReader extends ReaderInterface break 2; case "\r": case "\n": + if (empty($curToken)) { + continue 2; + } break 2; default: $curToken .= $curChar; @@ -64,13 +67,12 @@ class StringReader extends ReaderInterface $this->currentPosition = $this->nextPosition; while ($curChar = $this->getNextChar($this->nextPosition)) { $this->nextPosition++; - $this->currentLinePosition++; switch ($curChar) { // TODO: 注释跳过 case " ": // 如果开始的时候就有空白,跳过它 if (empty($curToken)) { - $this->currentPosition++; + $this->moveCursorToNextChar(); continue 2; } // 否则就结束(已经匹配完成) @@ -78,17 +80,24 @@ class StringReader extends ReaderInterface case "\r": if ($this->getNextChar($this->nextPosition + 1) === "\n") { // CRLF换行 + $this->moveCursorToNextChar(); $this->nextPosition++; } // CR换行 - $this->currentLine++; - $this->currentLinePosition = 0; - break 2; + $this->moveCursorToNextLine(); + if (empty($curToken)) { + continue 2; + } else { + break 2; + } case "\n": // LF换行 - $this->currentLine++; - $this->currentLinePosition = 0; - break 2; + $this->moveCursorToNextLine(); + if (empty($curToken)) { + continue 2; + } else { + break 2; + } default: $curToken .= $curChar; } @@ -116,7 +125,7 @@ class StringReader extends ReaderInterface break 2; } } - $this->nextPosition = $curPos + 1; + $this->nextPosition = $curPos; $this->currentLine++; $this->currentLinePosition = 0; return $this->moveToNextToken(); diff --git a/tests/Reader/StringReaderTest.php b/tests/Reader/StringReaderTest.php index 90e36f6..428de43 100644 --- a/tests/Reader/StringReaderTest.php +++ b/tests/Reader/StringReaderTest.php @@ -12,12 +12,14 @@ use PHPUnit\Framework\TestCase; class StringReaderTest extends TestCase { + protected $readerWithCrLf; protected $readerWithCn; protected $reader; protected function setUp(): void { $this->reader = new StringReader(" Ahhh This Is 一个 新的 TOken"); $this->readerWithCn = new StringReader(" 中文 这是 Is 一个 新的 TOken"); + $this->readerWithCrLf = new StringReader(" 中文 \r\n\r 这是 \r Is \n 一个 新的 TOken"); } public function testGetNextChar() @@ -46,26 +48,29 @@ class StringReaderTest extends TestCase * @date 2020/12/18 14:16 * @depends testGetNextChar * @depends testGetCurrentToken + * @depends testGetNextToken */ public function testMoveToNextToken() { $this->reader->reset(); $oldCurToken = $this->reader->getCurrentToken(); $oldNextPos = $this->reader->getNextPosition(); + $oldNextToken = $this->reader->getNextToken(); $this->reader->moveToNextToken(); $this->assertNotEquals($oldCurToken, $this->reader->getCurrentPosition(), "CurToken与旧CurToken相同"); $this->assertNotEquals($oldNextPos, $this->reader->getNextPosition(), "NextPos与旧NextPos相同"); - $this->assertEquals('This', $this->reader->getCurrentToken(), "不匹配"); + $this->assertEquals($oldNextToken, $this->reader->getCurrentToken(), "不匹配"); $this->assertEquals(7, $this->reader->getCurrentPosition(), "CurPos与预计不符"); $this->assertNotEquals($this->reader->getNextPosition(), $this->reader->getCurrentPosition(), "CurPos与NextPos相同"); // CJK Support $this->readerWithCn->reset(); $oldCurTokenCn = $this->readerWithCn->getCurrentToken(); $oldNextPosCn = $this->readerWithCn->getNextPosition(); + $oldNextTokenCn = $this->readerWithCn->getNextToken(); $this->readerWithCn->moveToNextToken(); $this->assertNotEquals($oldCurTokenCn, $this->readerWithCn->getCurrentPosition(), "CurToken与旧CurToken相同"); $this->assertNotEquals($oldNextPosCn, $this->readerWithCn->getNextPosition(), "NextPos与旧NextPos相同"); - $this->assertEquals('这是', $this->readerWithCn->getCurrentToken(), "不匹配"); + $this->assertEquals($oldNextTokenCn, $this->readerWithCn->getCurrentToken(), "不匹配"); $this->assertEquals(5, $this->readerWithCn->getCurrentPosition(), "CurPos与预计不符"); } @@ -85,4 +90,37 @@ class StringReaderTest extends TestCase $this->assertEquals($curPos, $this->reader->getCurrentPosition(), "CurPos不可以发生变化"); $this->assertEquals($nextPos, $this->reader->getNextPosition(), "NextPos不可以发生变化"); } + + public function testSkipCurrentLine() + { + $this->readerWithCrLf->resetCursor(); + $this->readerWithCrLf->skipCurrentLine(); + // moveToNextToken又移动了 + $this->assertEquals(3, $this->readerWithCrLf->getCurrentLine(), "行号不匹配"); + $this->assertEquals(1, $this->readerWithCrLf->getCurrentLinePosition(), "CLPos不匹配"); + $this->assertEquals("这是", $this->readerWithCrLf->getCurrentToken(), "Token不匹配"); + $this->assertEquals(8, $this->readerWithCrLf->getCurrentPosition(), "CurPos不匹配"); + $this->readerWithCrLf->skipCurrentLine(); + $this->assertEquals(4, $this->readerWithCrLf->getCurrentLine(), "行号不匹配"); + $this->assertEquals(1, $this->readerWithCrLf->getCurrentLinePosition(), "CLPos不匹配"); + $this->assertEquals("Is", $this->readerWithCrLf->getCurrentToken(), "Token不匹配"); + $this->assertEquals(13, $this->readerWithCrLf->getCurrentPosition(), "CurPos不匹配"); + $this->readerWithCrLf->skipCurrentLine(); + $this->assertEquals(5, $this->readerWithCrLf->getCurrentLine(), "行号不匹配"); + $this->assertEquals(1, $this->readerWithCrLf->getCurrentLinePosition(), "CLPos不匹配"); + $this->assertEquals("一个", $this->readerWithCrLf->getCurrentToken(), "Token不匹配"); + $this->assertEquals(18, $this->readerWithCrLf->getCurrentPosition(), "CurPos不匹配"); + } + + public function testResetCursor() + { + $this->reader->moveToNextToken(); + $curPos = $this->reader->getCurrentPosition(); + $nextPos = $this->reader->getNextPosition(); + $string = $this->reader->getCurrentToken(); + $this->reader->resetCursor(); + $this->assertNotEquals($curPos, $this->reader->getCurrentPosition(), "CurPos未发生变化"); + $this->assertNotEquals($nextPos, $this->reader->getNextPosition(), "NextPos未发生变化"); + $this->assertNotEquals($string, $this->reader->getCurrentToken(), "CurToken未发生变化"); + } }