Skip to content

Instantly share code, notes, and snippets.

@m3m0r7
Created July 24, 2020 10:28
Show Gist options
  • Save m3m0r7/b2a589f3b7c202a57814147c2f08fbb2 to your computer and use it in GitHub Desktop.
Save m3m0r7/b2a589f3b7c202a57814147c2f08fbb2 to your computer and use it in GitHub Desktop.
<?php
declare(strict_types=1);
class Node
{
protected string $text;
protected array $params;
public function __construct(string $text, ...$params)
{
$this->text = $text;
$this->params = $params;
}
}
class Heading extends Node
{
}
class Bold extends Node
{
}
class Italic extends Node
{
}
class Text extends Node
{
}
class Parser
{
protected string $text;
protected int $size;
public function __construct(string $text)
{
$this->text = $text;
$this->size = mb_strlen($this->text);
}
public function parse(): array
{
$nodes = [];
$line = 1;
$linePos = 0;
$buffer = '';
$addTextNode = function () use (&$buffer, &$nodes) {
if ($buffer === '') {
return;
}
$nodes[] = new Text($buffer);
$buffer = '';
};
for ($i = 0; $i < $this->size; $i++, $linePos++) {
$char = mb_substr($this->text, $i, 1);
switch ($char) {
case '#':
if ($linePos !== 0) {
$buffer .= $char;
break;
}
$headingSize = $this->readSameToken('#', $i);
$addTextNode();
$nodes[] = new Heading(
ltrim($this->readToLineBreak($i)),
strlen($headingSize)
);
break;
case '*':
$asterSize = strlen($this->readSameToken('*', $i));
$class = null;
if ($asterSize === 1) {
$text = $this->readToToken('*', $i);
$class = Bold::class;
} elseif ($asterSize === 2) {
$text = $this->readToToken('**', $i);
$class = Italic::class;
}
$addTextNode();
$nodes[] = new $class($text);
$i++;
break;
case "\n":
$line++;
$linePos = -1;
break;
default:
$buffer .= $char;
break;
}
}
$addTextNode();
return $nodes;
}
protected function readToLineBreak(&$i): string
{
return $this->readToToken("\n", $i);
}
protected function readToToken(string $token, &$i): string
{
$text = '';
$tokenSize = mb_strlen($token);
for (; $i < $this->size; $i++) {
$char = mb_substr($this->text, $i, $tokenSize);
if ($char !== $token) {
$text .= mb_substr($this->text, $i, 1);
} else {
// Back
$i += $tokenSize - 1;
$i--;
break;
}
}
return $text;
}
protected function readSameToken(string $token, &$i): string
{
$text = '';
$tokenSize = mb_strlen($token);
for (; $i < $this->size; $i++) {
$char = mb_substr($this->text, $i, $tokenSize);
if ($char !== $token) {
$i += $tokenSize - 1;
break;
}
$text .= mb_substr($this->text, $i, 1);
}
return $text;
}
}
/**
array(9) {
[0]=>
object(Heading)#3 (2) {
["text":protected]=>
string(4) "aaaa"
["params":protected]=>
array(1) {
[0]=>
int(1)
}
}
[1]=>
object(Heading)#4 (2) {
["text":protected]=>
string(4) "aaaa"
["params":protected]=>
array(1) {
[0]=>
int(2)
}
}
[2]=>
object(Text)#5 (2) {
["text":protected]=>
string(8) "hogehoge"
["params":protected]=>
array(0) {
}
}
[3]=>
object(Italic)#6 (2) {
["text":protected]=>
string(8) "biyobiyo"
["params":protected]=>
array(0) {
}
}
[4]=>
object(Text)#7 (2) {
["text":protected]=>
string(4) "nyan"
["params":protected]=>
array(0) {
}
}
[5]=>
object(Bold)#8 (2) {
["text":protected]=>
string(4) "neko"
["params":protected]=>
array(0) {
}
}
[6]=>
object(Text)#9 (2) {
["text":protected]=>
string(4) "guee"
["params":protected]=>
array(0) {
}
}
[7]=>
object(Heading)#10 (2) {
["text":protected]=>
string(4) "aaaa"
["params":protected]=>
array(1) {
[0]=>
int(3)
}
}
[8]=>
object(Text)#11 (2) {
["text":protected]=>
string(5) "nya-n"
["params":protected]=>
array(0) {
}
}
}
*/
var_dump(
(new Parser(
$markdown = <<< _
# aaaa
## aaaa
hogehoge**biyobiyo**nyan*neko*guee
### aaaa
nya-n
_
))->parse()
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment