120 lines
3.1 KiB
PHP
120 lines
3.1 KiB
PHP
<?php
|
|
namespace nur\b\io;
|
|
|
|
use nur\b\coll\AbstractIterator;
|
|
use nur\str;
|
|
|
|
class StringReader extends AbstractIterator implements IReader {
|
|
use Treader;
|
|
|
|
static final function next_line(string $string, int $index, ?int $length=null): ?array {
|
|
if ($length === null) $length = strlen($string);
|
|
$poscr = strpos($string, "\r", $index);
|
|
$poslf = strpos($string, "\n", $index);
|
|
if ($poscr !== false && $poslf !== false) {
|
|
$pos = min($poscr, $poslf);
|
|
} elseif ($poscr !== false) {
|
|
$pos = $poscr;
|
|
} elseif ($poslf !== false) {
|
|
$pos = $poslf;
|
|
} else {
|
|
$pos = false;
|
|
}
|
|
# ligne se terminant par CR[LF]
|
|
if ($pos !== false && $pos === $poscr) {
|
|
$pos++;
|
|
if ($pos < $length && $string[$pos] == "\n") $pos++;
|
|
$line = substr($string, $index, $pos - $index);
|
|
return [str::strip_nl($line), $pos];
|
|
}
|
|
# ligne se terminant par LF
|
|
if ($pos !== false && $pos === $poslf) {
|
|
$pos++;
|
|
$line = substr($string, $index, $pos - $index);
|
|
return [str::strip_nl($line), $pos];
|
|
}
|
|
# ligne sans caractère de fin
|
|
return [substr($string, $index), $length];
|
|
}
|
|
|
|
function __construct(?string $string=null, int $index=0) {
|
|
$this->setString($string, $index);
|
|
}
|
|
|
|
/** @var string la chaine à lire */
|
|
private $string;
|
|
|
|
/** @var int longueur de la chaine */
|
|
private $length;
|
|
|
|
/** @var int position de lecture dans la chaine */
|
|
private $index;
|
|
|
|
private static function fix_index(int $index, int $length): int {
|
|
if ($index < 0) {
|
|
if ($length > 0) {
|
|
while ($index < 0) $index += $length;
|
|
} else {
|
|
$index = 0;
|
|
}
|
|
}
|
|
if ($index > $length) $index = $length;
|
|
return $index;
|
|
}
|
|
|
|
function setString(?string $string, int $index=0) {
|
|
if ($string === null) $string = "";
|
|
$length = strlen($string);
|
|
$index = self::fix_index($index, $length);
|
|
|
|
$this->string = $string;
|
|
$this->index = $index;
|
|
$this->length = $length;
|
|
}
|
|
|
|
function close(bool $close=true): void {
|
|
}
|
|
|
|
function getResource() {
|
|
return null;
|
|
}
|
|
|
|
function appendFilter(string $filterName, ?int $readWrite=null, $params=null): void {
|
|
}
|
|
|
|
function prependFilter(string $filterName, ?int $readWrite=null, $params=null): void {
|
|
}
|
|
|
|
function setEncodingFilter(string $from, string $to = "utf-8"): void {
|
|
}
|
|
|
|
function seek(int $index=0, int $whence=SEEK_SET): int {
|
|
if ($whence == SEEK_CUR) {
|
|
$index = $this->index + $index;
|
|
} elseif ($whence == SEEK_END) {
|
|
$index = $this->length - $index;
|
|
}
|
|
return $this->index = self::fix_index($index, $this->length);
|
|
}
|
|
|
|
function readLine(): string {
|
|
$index = $this->index;
|
|
$length = $this->length;
|
|
if ($index == $length) throw EOFException::no_more_data();
|
|
[$line, $this->index] = self::next_line($this->string, $index, $length);
|
|
return $line;
|
|
}
|
|
|
|
protected function _next(&$key) {
|
|
return $this->readLine();
|
|
}
|
|
function key() { return $this->_key(); }
|
|
function current() { return $this->_current(); }
|
|
|
|
function getContents(bool $close=true): string {
|
|
$contents = substr($this->string, $this->index);
|
|
$this->index = $this->length;
|
|
return $contents;
|
|
}
|
|
}
|