Skip to content

Commit 6e260af

Browse files
committed
[String] bytesAt() and codePointsAt()
1 parent a306d99 commit 6e260af

10 files changed

+149
-8
lines changed

src/Symfony/Component/String/AbstractString.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ public function beforeLast($needle, bool $includeNeedle = false, int $offset = 0
225225
return $this->slice(0, $i);
226226
}
227227

228+
/**
229+
* @return int[]
230+
*/
231+
abstract public function bytesAt(int $offset): array;
232+
228233
/**
229234
* @return static
230235
*/

src/Symfony/Component/String/AbstractUnicodeString.php

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,13 @@ public function ascii(array $rules = []): self
149149
return $str;
150150
}
151151

152+
public function bytesAt(int $offset): array
153+
{
154+
$str = $this->slice($offset, 1);
155+
156+
return '' === $str->string ? [] : array_values(unpack('C*', $str->string));
157+
}
158+
152159
public function camel(): parent
153160
{
154161
$str = clone $this;
@@ -159,12 +166,11 @@ public function camel(): parent
159166
return $str;
160167
}
161168

162-
public function codePoint(int $offset = 0): ?int
163-
{
164-
$str = $offset ? $this->slice($offset, 1) : $this;
165169

166-
return '' === $str->string ? null : mb_ord($str->string);
167-
}
170+
/**
171+
* @return int[]
172+
*/
173+
abstract public function codePointsAt(int $offset): array;
168174

169175
public function folded(bool $compat = true): parent
170176
{

src/Symfony/Component/String/ByteString.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@ public static function fromRandom(int $length = 16): self
4343
return new static(substr($string, 0, $length));
4444
}
4545

46-
public function byteCode(int $offset = 0): ?int
46+
public function bytesAt(int $offset): array
4747
{
48-
$str = $offset ? $this->slice($offset, 1) : $this;
48+
$str = $this->string[$offset] ?? '';
4949

50-
return '' === $str->string ? null : \ord($str->string);
50+
return '' === $str ? [] : [\ord($str)];
5151
}
5252

5353
public function append(string ...$suffix): parent

src/Symfony/Component/String/CodePointString.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ public function chunk(int $length = 1): array
7575
return $chunks;
7676
}
7777

78+
public function codePointsAt(int $offset): array
79+
{
80+
$str = $offset ? $this->slice($offset, 1) : $this;
81+
82+
return '' === $str->string ? [] : [mb_ord($str->string)];
83+
}
84+
7885
public function endsWith($suffix): bool
7986
{
8087
if ($suffix instanceof AbstractString) {

src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,27 @@ public function testCreateFromEmptyString()
3434
$this->assertTrue($instance->isEmpty());
3535
}
3636

37+
/**
38+
* @dataProvider provideBytesAt
39+
*/
40+
public function testBytesAt(array $expected, string $string, int $offset, int $form = null)
41+
{
42+
$instance = static::createFromString($string);
43+
$instance = $form ? $instance->normalize($form) : $instance;
44+
45+
$this->assertSame($expected, $instance->bytesAt($offset));
46+
}
47+
48+
public static function provideBytesAt(): array
49+
{
50+
return [
51+
[[], '', 0],
52+
[[], 'a', 1],
53+
[[0x62], 'abc', 1],
54+
[[0x63], 'abcde', -3],
55+
];
56+
}
57+
3758
/**
3859
* @dataProvider provideLength
3960
*/

src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,40 @@ public function provideCreateFromCodePoint(): array
3434
];
3535
}
3636

37+
public static function provideBytesAt(): array
38+
{
39+
return array_merge(
40+
parent::provideBytesAt(),
41+
[
42+
[[0xC3, 0xA4], "Späßchen", 2],
43+
[[0xC3, 0x9F], "Späßchen", -5],
44+
]
45+
);
46+
}
47+
48+
/**
49+
* @dataProvider provideCodePointsAt
50+
*/
51+
public function testCodePointsAt(array $expected, string $string, int $offset, int $form = null)
52+
{
53+
$instance = static::createFromString($string);
54+
$instance = $form ? $instance->normalize($form) : $instance;
55+
56+
$this->assertSame($expected, $instance->codePointsAt($offset));
57+
}
58+
59+
public static function provideCodePointsAt(): array
60+
{
61+
return [
62+
[[], '', 0],
63+
[[], 'a', 1],
64+
[[0x53], 'Späßchen', 0],
65+
[[0xE4], 'Späßchen', 2],
66+
[[0xDF], 'Späßchen', -5],
67+
[[0x260E], '☢☎❄', 1],
68+
];
69+
}
70+
3771
public static function provideLength(): array
3872
{
3973
return [

src/Symfony/Component/String/Tests/ByteStringTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ protected static function createFromString(string $string): AbstractString
2121
return new ByteString($string);
2222
}
2323

24+
public static function provideBytesAt(): array
25+
{
26+
return array_merge(
27+
parent::provideBytesAt(),
28+
[
29+
[[0xC3], "Späßchen", 2],
30+
[[0x61], "Spa\u{0308}ßchen", 2],
31+
[[0xCC], "Spa\u{0308}ßchen", 3],
32+
[[0xE0], 'नमस्ते', 6],
33+
]
34+
);
35+
}
36+
2437
public static function provideLength(): array
2538
{
2639
return array_merge(

src/Symfony/Component/String/Tests/CodePointStringTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,28 @@ public static function provideLength(): array
3131
]
3232
);
3333
}
34+
35+
public static function provideBytesAt(): array
36+
{
37+
return array_merge(
38+
parent::provideBytesAt(),
39+
[
40+
[[0x61], "Spa\u{0308}ßchen", 2],
41+
[[0xCC, 0x88], "Spa\u{0308}ßchen", 3],
42+
[[0xE0, 0xA5, 0x8D], 'नमस्ते', 3],
43+
]
44+
);
45+
}
46+
47+
public static function provideCodePointsAt(): array
48+
{
49+
return array_merge(
50+
parent::provideCodePointsAt(),
51+
[
52+
[[0x61], "Spa\u{0308}ßchen", 2],
53+
[[0x0308], "Spa\u{0308}ßchen", 3],
54+
[[0x094D], 'नमस्ते', 3],
55+
]
56+
);
57+
}
3458
}

src/Symfony/Component/String/Tests/UnicodeStringTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,30 @@ public static function provideChunk(): array
7373
);
7474
}
7575

76+
public static function provideBytesAt(): array
77+
{
78+
return array_merge(
79+
parent::provideBytesAt(),
80+
[
81+
[[0xC3, 0xA4], "Spa\u{0308}ßchen", 2],
82+
[[0x61, 0xCC, 0x88], "Spa\u{0308}ßchen", 2, UnicodeString::NFD],
83+
[[0xE0, 0xA4, 0xB8, 0xE0, 0xA5, 0x8D], 'नमस्ते', 2],
84+
]
85+
);
86+
}
87+
88+
public static function provideCodePointsAt(): array
89+
{
90+
return array_merge(
91+
parent::provideCodePointsAt(),
92+
[
93+
[[0xE4], "Spa\u{0308}ßchen", 2],
94+
[[0x61, 0x0308], "Spa\u{0308}ßchen", 2, UnicodeString::NFD],
95+
[[0x0938, 0x094D], 'नमस्ते', 2],
96+
]
97+
);
98+
}
99+
76100
public static function provideLower(): array
77101
{
78102
return array_merge(

src/Symfony/Component/String/UnicodeString.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ public function chunk(int $length = 1): array
8484
return $chunks;
8585
}
8686

87+
public function codePointsAt(int $offset): array
88+
{
89+
$str = $this->slice($offset, 1);
90+
91+
return '' === $str->string ? [] : array_map('mb_ord', preg_split('//u', $str->string, -1, PREG_SPLIT_NO_EMPTY));
92+
}
93+
8794
public function endsWith($suffix): bool
8895
{
8996
if ($suffix instanceof AbstractString) {

0 commit comments

Comments
 (0)