Skip to content

Commit 704368c

Browse files
author
Hugo Hamon
committed
[Utf8] added Bytes, CodePoints and Graphemes implementations.
1 parent df3836d commit 704368c

File tree

12 files changed

+2104
-4
lines changed

12 files changed

+2104
-4
lines changed

src/Symfony/Component/Utf8/Bytes.php

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Utf8;
13+
14+
use Symfony\Component\Utf8\Exception\InvalidArgumentException;
15+
16+
final class Bytes implements GenericStringInterface, \Countable
17+
{
18+
private $string = '';
19+
20+
public static function fromString(string $string): self
21+
{
22+
$bytes = new self();
23+
$bytes->string = $string;
24+
25+
return $bytes;
26+
}
27+
28+
public static function fromCharCode(int ...$codes): self
29+
{
30+
$string = '';
31+
foreach ($codes as $code) {
32+
$string.= chr($code);
33+
}
34+
35+
$bytes = new self();
36+
$bytes->string = $string;
37+
38+
return $bytes;
39+
}
40+
41+
public function __toString()
42+
{
43+
return $this->string;
44+
}
45+
46+
/**
47+
* @see \Countable::count
48+
*/
49+
public function count(): int
50+
{
51+
return strlen($this->string);
52+
}
53+
54+
public function length(): int
55+
{
56+
return strlen($this->string);
57+
}
58+
59+
public function isEmpty(): bool
60+
{
61+
return '' === $this->string;
62+
}
63+
64+
/**
65+
* {@inheritdoc}
66+
*/
67+
public function explode(string $delimiter, int $limit = null): array
68+
{
69+
if ('' === $delimiter) {
70+
throw new InvalidArgumentException('Passing an empty delimiter is not supported by this method. Use getIterator() method instead.');
71+
}
72+
73+
$chunks = array();
74+
foreach (explode($delimiter, $this->string, $limit ?: PHP_INT_MAX) as $i => $string) {
75+
$chunks[$i] = $chunk = clone $this;
76+
$chunk->string = $string;
77+
}
78+
79+
return $chunks;
80+
}
81+
82+
/**
83+
* {@inheritdoc}
84+
*/
85+
public function toLowerCase(): self
86+
{
87+
$result = clone $this;
88+
$result->string = strtolower($this->string);
89+
90+
return $result;
91+
}
92+
93+
/**
94+
* {@inheritdoc}
95+
*/
96+
public function toUpperCase(): self
97+
{
98+
$result = clone $this;
99+
$result->string = strtoupper($this->string);
100+
101+
return $result;
102+
}
103+
104+
/**
105+
* {@inheritdoc}
106+
*/
107+
public function substr(int $start = 0, int $length = null): self
108+
{
109+
$result = clone $this;
110+
$result->string = substr($this->string, $start, $length);
111+
112+
return $result;
113+
}
114+
115+
/**
116+
* {@inheritdoc}
117+
*/
118+
public function trim(string $charsList = null): self
119+
{
120+
$result = clone $this;
121+
$result->string = trim($this->string, $charsList ?: " \t\n\r\0\x0B");
122+
123+
return $result;
124+
}
125+
126+
/**
127+
* {@inheritdoc}
128+
*/
129+
public function trimLeft(string $charsList = null): self
130+
{
131+
$result = clone $this;
132+
$result->string = ltrim($this->string, $charsList ?: " \t\n\r\0\x0B");
133+
134+
return $result;
135+
}
136+
137+
/**
138+
* {@inheritdoc}
139+
*/
140+
public function trimRight(string $charsList = null): self
141+
{
142+
$result = clone $this;
143+
$result->string = rtrim($this->string, $charsList ?: " \t\n\r\0\x0B");
144+
145+
return $result;
146+
}
147+
148+
public function startsWith(string $prefix, int $offset = 0): bool
149+
{
150+
if ($offset < 0 && PHP_VERSION_ID < 70100) {
151+
$offset = strlen($this->string) - abs($offset);
152+
}
153+
154+
return $offset === strpos($this->string, $prefix, $offset);
155+
}
156+
157+
public function endsWith(string $suffix): bool
158+
{
159+
$suffix = (string) $suffix;
160+
161+
return substr($this->string, -strlen($suffix)) === $suffix;
162+
}
163+
164+
public function getIterator(int $maxChunkLength = 1): \Generator
165+
{
166+
if ($maxChunkLength < 1) {
167+
throw new InvalidArgumentException('The maximum length of each segment must be greater than zero.');
168+
}
169+
170+
if ('' === $this->string) {
171+
yield clone $this;
172+
}
173+
174+
foreach (str_split($this->string, $maxChunkLength) as $key => $char) {
175+
$clone = clone $this;
176+
$clone->string = $char;
177+
yield $key => $clone;
178+
}
179+
}
180+
181+
public function append(string $suffix): self
182+
{
183+
$result = clone $this;
184+
$result->string.= $suffix;
185+
186+
return $result;
187+
}
188+
189+
public function prepend(string $prefix): self
190+
{
191+
$result = clone $this;
192+
$result->string = $prefix.$result->string;
193+
194+
return $result;
195+
}
196+
197+
public function toCodePoints(): CodePoints
198+
{
199+
return CodePoints::fromString($this->string);
200+
}
201+
202+
public function toGraphemes(): Graphemes
203+
{
204+
return Graphemes::fromString($this->string);
205+
}
206+
}

0 commit comments

Comments
 (0)