diff --git a/src/Neon/Node/StringNode.php b/src/Neon/Node/StringNode.php index ffee11f6..6728b1a6 100644 --- a/src/Neon/Node/StringNode.php +++ b/src/Neon/Node/StringNode.php @@ -80,16 +80,18 @@ function (array $m): string { public function toString(): string { if (strpos($this->value, "\n") === false) { - return "'" . str_replace("'", "''", $this->value) . "'"; + return preg_match('~[\x00-\x08\x0B-\x1F]~', $this->value) + ? json_encode($this->value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) + : "'" . str_replace("'", "''", $this->value) . "'"; - } elseif (preg_match('~\n[\t ]+\'{3}~', $this->value)) { - $s = json_encode($this->value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + } elseif (preg_match('~[\x00-\x08\x0B-\x1F]|\n[\t ]+\'{3}~', $this->value)) { + $s = substr(json_encode($this->value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 1, -1); $s = preg_replace_callback( '#[^\\\\]|\\\\(.)#s', function ($m) { return ['n' => "\n", 't' => "\t", '"' => '"'][$m[1] ?? ''] ?? $m[0]; }, - substr($s, 1, -1) + $s, ); $s = str_replace('"""', '""\"', $s); $delim = '"""'; diff --git a/tests/Neon/Encoder.phpt b/tests/Neon/Encoder.phpt index 8019c0e9..0794643e 100644 --- a/tests/Neon/Encoder.phpt +++ b/tests/Neon/Encoder.phpt @@ -164,3 +164,13 @@ Assert::same( '[]', Neon::encode([], Neon::BLOCK) ); + +Assert::same( + '"special \u0000 chars"', + Neon::encode("special \x00 chars", true), +); + +Assert::same( + "\"\"\"\n\tspecial\\r\n\tchars\n\"\"\"", + Neon::encode("special\r\nchars", true), +);