xref: /PHP-8.3/ext/intl/tests/grapheme2.phpt (revision 74859783)
1--TEST--
2grapheme()
3--EXTENSIONS--
4intl
5--SKIPIF--
6<?php if (version_compare(INTL_ICU_VERSION, '65.0') < 0) die('skip for ICU >= 65.0'); ?>
7--FILE--
8<?php
9
10/*
11 * Test grapheme functions (procedural only)
12 */
13
14function ut_main()
15{
16    $res_str = '';
17
18    $char_a_diaeresis = "\xC3\xA4";	// 'LATIN SMALL LETTER A WITH DIAERESIS' (U+00E4)
19    $char_a_ring = "\xC3\xA5";		// 'LATIN SMALL LETTER A WITH RING ABOVE' (U+00E5)
20    $char_o_diaeresis = "\xC3\xB6";    // 'LATIN SMALL LETTER O WITH DIAERESIS' (U+00F6)
21    $char_O_diaeresis = "\xC3\x96";    // 'LATIN CAPITAL LETTER O WITH DIAERESIS' (U+00D6)
22
23    $char_angstrom_sign = "\xE2\x84\xAB"; // 'ANGSTROM SIGN' (U+212B)
24    $char_A_ring = "\xC3\x85";	// 'LATIN CAPITAL LETTER A WITH RING ABOVE' (U+00C5)
25
26    $char_ohm_sign = "\xE2\x84\xA6";	// 'OHM SIGN' (U+2126)
27    $char_omega = "\xCE\xA9";  // 'GREEK CAPITAL LETTER OMEGA' (U+03A9)
28
29    $char_combining_ring_above = "\xCC\x8A";  // 'COMBINING RING ABOVE' (U+030A)
30
31    $char_fi_ligature = "\xEF\xAC\x81";  // 'LATIN SMALL LIGATURE FI' (U+FB01)
32
33    $char_long_s_dot = "\xE1\xBA\x9B";	// 'LATIN SMALL LETTER LONG S WITH DOT ABOVE' (U+1E9B)
34
35    // the word 'hindi' using Devanagari characters:
36    $hindi = "\xe0\xa4\xb9\xe0\xa4\xbf\xe0\xa4\xa8\xe0\xa5\x8d\xe0\xa4\xa6\xe0\xa5\x80";
37
38    $char_a_ring_nfd = "a\xCC\x8A";
39    $char_A_ring_nfd = "A\xCC\x8A";
40    $char_o_diaeresis_nfd = "o\xCC\x88";
41    $char_O_diaeresis_nfd = "O\xCC\x88";
42    $char_diaeresis = "\xCC\x88";
43
44    //=====================================================================================
45    $res_str .= "\n" . 'function grapheme_strlen($string) {}' . "\n\n";
46
47
48    $res_str .= "\"hindi\" in devanagari strlen " . grapheme_strlen($hindi) . "\n";
49    $res_str .= "\"ab\" + \"hindi\" + \"cde\" strlen " . grapheme_strlen('ab' . $hindi . 'cde') . "\n";
50    $res_str .= "\"\" strlen " . grapheme_strlen("") . "\n";
51    $res_str .= "char_a_ring_nfd strlen " . grapheme_strlen($char_a_ring_nfd) . "\n";
52    $res_str .= "char_a_ring_nfd + \"bc\" strlen " . grapheme_strlen($char_a_ring_nfd . 'bc') . "\n";
53    $res_str .= "\"abc\" strlen " . grapheme_strlen('abc') . "\n";
54
55
56    //=====================================================================================
57    $res_str .= "\n" . 'function grapheme_strpos($haystack, $needle, $offset = 0) {}' . "\n\n";
58
59    $tests = array(
60        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o", "o", 5 ),
61        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "o", "false" ),
62        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, $char_o_diaeresis_nfd, 4 ),
63        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, 2 ),
64        array( "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, 1 ),
65        array( "abc", $char_a_ring_nfd, "false" ),
66        array( $char_a_ring_nfd . "bc", "a", "false" ),
67        array( "abc", "d", "false" ),
68        array( "abc", "c", 2 ),
69        array( "abc", "b", 1 ),
70        array( "abc", "a", 0 ),
71        array( "abc", "a", 0, 0 ),
72        array( "abc", "a", 1, "false" ),
73        array( "abc", "a", -1, "false" ),
74        array( "ababc", "a", 1, 2 ),
75        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o", "o", 2, 6 ),
76        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o", "o", -1, 6 ),
77        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o", "o", -5, 6 ),
78        array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, 2, 3 ),
79        array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, -4, 3 ),
80
81        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "opq", "op", 5 ),
82        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "opq", "opq", 5 ),
83        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "abc", "false" ),
84        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "bc" . $char_o_diaeresis_nfd, $char_o_diaeresis_nfd . "bc" . $char_o_diaeresis_nfd, 4 ),
85        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd . "bc", 2 ),
86        array( "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd . "bc", 1 ),
87        array( "abc", $char_a_ring_nfd . "bc", "false" ),
88        array( $char_a_ring_nfd . "bc", "abcdefg", "false" ),
89        array( "abc", "defghijklmnopq", "false" ),
90        array( "abc", "ab", 0 ),
91        array( "abc", "bc", 1 ),
92        array( "abc", "abc", 0 ),
93        array( "abc", "abcd", "false" ),
94        array( "abc", "ab", 0, 0 ),
95        array( "abc", "abc", 0, 0 ),
96        array( "abc", "abc", 1, "false" ),
97        array( "ababc", "ab", 1, 2 ),
98        array( "ababc", "abc", 1, 2 ),
99        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o" . $char_a_ring_nfd . "bc", "o" . $char_a_ring_nfd . "bc", 2, 6 ),
100        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o" . $char_a_ring_nfd . "bc", "o" . $char_a_ring_nfd . "bc", -8, 6 ),
101        array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_a_ring_nfd . "bc" . $char_a_ring_nfd . "def", $char_a_ring_nfd . "bc" . $char_a_ring_nfd, 2, 3 ),
102    );
103
104    foreach( $tests as $test ) {
105        $arg1 = urlencode($test[1]);
106        $arg0 = urlencode($test[0]);
107        $res_str .= "find \"$arg1\" in \"$arg0\" - grapheme_strpos";
108        if ( 3 == count( $test ) ) {
109            $result = grapheme_strpos($test[0], $test[1]);
110        }
111        else {
112            $res_str .= " from $test[2]";
113            $result = grapheme_strpos($test[0], $test[1], $test[2]);
114        }
115        $res_str .= " = ";
116        if ( $result === false ) {
117            $res_str .= 'false';
118        }
119        else {
120            $res_str .= $result;
121        }
122        $res_str .= " == " . $test[count($test)-1] . check_result($result, $test[count($test)-1]) . "\n";
123    }
124
125    //=====================================================================================
126    $res_str .= "\n" . 'function grapheme_stripos($haystack, $needle, $offset = 0) {}' . "\n\n";
127
128    $tests = array(
129        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O", "o", 2, 6 ),
130        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Oo", "o", -6, 6 ),
131        array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_A_ring_nfd . "bc", $char_a_ring_nfd, 2, 3 ),
132        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O", "o", 5 ),
133        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "O", "false" ),
134        array( "a" . $char_a_ring_nfd . "bc" . $char_O_diaeresis_nfd, $char_o_diaeresis_nfd, 4 ),
135        array( "a" . $char_a_ring_nfd . "bc" . $char_O_diaeresis_nfd, $char_o_diaeresis_nfd, -1, 4 ),
136        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "bc", $char_A_ring_nfd, 2 ),
137        array( "a" . $char_A_ring_nfd . "bc", $char_a_ring_nfd, 1 ),
138        array( "Abc", $char_a_ring_nfd, "false" ),
139        array( $char_a_ring_nfd . "bc", "A", "false" ),
140        array( "abc", "D", "false" ),
141        array( "abC", "c", 2 ),
142        array( "abc", "B", 1 ),
143        array( "Abc", "a", 0 ),
144        array( "abc", "A", 0, 0 ),
145        array( "Abc", "a", 1, "false" ),
146        array( "ababc", "A", 1, 2 ),
147
148        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", "oP", 5 ),
149        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", "opQ", 5 ),
150        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "abc", "false" ),
151        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "bC" . $char_o_diaeresis_nfd, $char_O_diaeresis_nfd . "bc" . $char_o_diaeresis_nfd, 4 ),
152        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "Bc", $char_A_ring_nfd . "bc", 2 ),
153        array( "a" . $char_a_ring_nfd . "BC", $char_a_ring_nfd . "bc", 1 ),
154        array( "abc", $char_a_ring_nfd . "BC", "false" ),
155        array( $char_a_ring_nfd . "BC", "aBCdefg", "false" ),
156        array( "aBC", "Defghijklmnopq", "false" ),
157        array( "abC", "Ab", 0 ),
158        array( "aBC", "bc", 1 ),
159        array( "abC", "Abc", 0 ),
160        array( "abC", "aBcd", "false" ),
161        array( "ABc", "ab", 0, 0 ),
162        array( "aBc", "abC", 0, 0 ),
163        array( "abc", "aBc", 1, "false" ),
164        array( "ABabc", "AB", 1, 2 ),
165        array( "ABabc", "AB", -4, 2 ),
166        array( "abaBc", "aBc", 1, 2 ),
167        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o" . $char_A_ring_nfd . "bC", "O" . $char_a_ring_nfd . "bC", 2, 6 ),
168        array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_A_ring_nfd . "bC" . $char_a_ring_nfd . "def", $char_a_ring_nfd . "Bc" . $char_a_ring_nfd, 2, 3 ),
169    );
170
171    foreach( $tests as $test ) {
172        $arg1 = urlencode($test[1]);
173        $arg0 = urlencode($test[0]);
174        $res_str .= "find \"$arg1\" in \"$arg0\" - grapheme_stripos";
175        if ( 3 == count( $test ) ) {
176            $result = grapheme_stripos($test[0], $test[1]);
177        }
178        else {
179            $res_str .= " from $test[2]";
180            $result = grapheme_stripos($test[0], $test[1], $test[2]);
181        }
182        $res_str .= " = ";
183        if ( $result === false ) {
184            $res_str .= 'false';
185        }
186        else {
187            $res_str .= $result;
188        }
189        $res_str .= " == " . $test[count($test)-1] . check_result($result, $test[count($test)-1]) . "\n";
190    }
191
192
193    //=====================================================================================
194    $res_str .= "\n" . 'function grapheme_strrpos($haystack, $needle, $offset = 0) {}' . "\n\n";
195
196
197    $tests = array(
198        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o", "o", 5 ),
199        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "o", "false" ),
200        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, $char_o_diaeresis_nfd, 4 ),
201        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, 2 ),
202        array( "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, 1 ),
203        array( "abc", $char_a_ring_nfd, "false" ),
204        array( $char_a_ring_nfd . "bc", "a", "false" ),
205        array( "abc", "d", "false" ),
206        array( "abc", "c", 2 ),
207        array( "abc", "b", 1 ),
208        array( "abc", "a", 0 ),
209        array( "abc", "a", 0, 0 ),
210        array( "abc", "a", 1, "false" ),
211        array( "ababc", "a", 1, 2 ),
212        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o", "o", 2, 6 ),
213        array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, 2, 3 ),
214
215        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "opq", "op", 5 ),
216        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "opq", "opq", 5 ),
217        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "abc", "false" ),
218        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "bc" . $char_o_diaeresis_nfd, $char_o_diaeresis_nfd . "bc" . $char_o_diaeresis_nfd, 4 ),
219        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd . "bc", 2 ),
220        array( "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd . "bc", 1 ),
221        array( "abc", $char_a_ring_nfd . "bc", "false" ),
222        array( $char_a_ring_nfd . "bc", "abcdefg", "false" ),
223        array( "abc", "defghijklmnopq", "false" ),
224        array( "abc", "ab", 0 ),
225        array( "abc", "bc", 1 ),
226        array( "abc", "abc", 0 ),
227        array( "abc", "abcd", "false" ),
228        array( "abc", "ab", 0, 0 ),
229        array( "abc", "abc", 0, 0 ),
230        array( "abc", "abc", 1, "false" ),
231        array( "ababc", "ab", 1, 2 ),
232        array( "ababc", "abc", 1, 2 ),
233        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o" . $char_a_ring_nfd . "bc", "o" . $char_a_ring_nfd . "bc", 2, 6 ),
234        array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_a_ring_nfd . "bc" . $char_a_ring_nfd . "def", $char_a_ring_nfd . "bc" . $char_a_ring_nfd, 2, 3 ),
235    );
236
237    foreach( $tests as $test ) {
238        $arg1 = urlencode($test[1]);
239        $arg0 = urlencode($test[0]);
240        $res_str .= "find \"$arg1\" in \"$arg0\" - grapheme_strrpos";
241        if ( 3 == count( $test ) ) {
242            $result = grapheme_strrpos($test[0], $test[1]);
243        }
244        else {
245            $res_str .= " from $test[2]";
246            $result = grapheme_strrpos($test[0], $test[1], $test[2]);
247        }
248        $res_str .= " = ";
249        if ( $result === false ) {
250            $res_str .= 'false';
251        }
252        else {
253            $res_str .= $result;
254        }
255        $res_str .= " == " . $test[count($test)-1] .  check_result($result, $test[count($test)-1]) . "\n";
256    }
257
258
259    //=====================================================================================
260    $res_str .= "\n" . 'function grapheme_strripos($haystack, $needle, $offset = 0) {}' . "\n\n";
261
262    $tests = array(
263        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O", "o", 2, 6 ),
264        array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_A_ring_nfd . "bc", $char_a_ring_nfd, 2, 3 ),
265        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O", "o", 5 ),
266        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "O", "false" ),
267        array( "a" . $char_a_ring_nfd . "bc" . $char_O_diaeresis_nfd, $char_o_diaeresis_nfd, 4 ),
268        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "bc", $char_A_ring_nfd, 2 ),
269        array( "a" . $char_A_ring_nfd . "bc", $char_a_ring_nfd, 1 ),
270        array( "Abc", $char_a_ring_nfd, "false" ),
271        array( $char_a_ring_nfd . "bc", "A", "false" ),
272        array( "abc", "D", "false" ),
273        array( "abC", "c", 2 ),
274        array( "abc", "B", 1 ),
275        array( "Abc", "a", 0 ),
276        array( "abc", "A", 0, 0 ),
277        array( "Abc", "a", 1, "false" ),
278        array( "ababc", "A", 1, 2 ),
279
280        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", "oP", 5 ),
281        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", "opQ", 5 ),
282        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "abc", "false" ),
283        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "bC" . $char_o_diaeresis_nfd, $char_O_diaeresis_nfd . "bc" . $char_o_diaeresis_nfd, 4 ),
284        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "Bc", $char_A_ring_nfd . "bc", 2 ),
285        array( "a" . $char_a_ring_nfd . "BC", $char_a_ring_nfd . "bc", 1 ),
286        array( "abc", $char_a_ring_nfd . "BC", "false" ),
287        array( $char_a_ring_nfd . "BC", "aBCdefg", "false" ),
288        array( "aBC", "Defghijklmnopq", "false" ),
289        array( "abC", "Ab", 0 ),
290        array( "aBC", "bc", 1 ),
291        array( "abC", "Abc", 0 ),
292        array( "abC", "aBcd", "false" ),
293        array( "ABc", "ab", 0, 0 ),
294        array( "aBc", "abC", 0, 0 ),
295        array( "abc", "aBc", 1, "false" ),
296        array( "ABabc", "AB", 1, 2 ),
297        array( "abaBc", "aBc", 1, 2 ),
298        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o" . $char_A_ring_nfd . "bC", "O" . $char_a_ring_nfd . "bC", 2, 6 ),
299        array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_A_ring_nfd . "bC" . $char_a_ring_nfd . "def", $char_a_ring_nfd . "Bc" . $char_a_ring_nfd, 2, 3 ),
300    );
301
302    foreach( $tests as $test ) {
303        $arg1 = urlencode($test[1]);
304        $arg0 = urlencode($test[0]);
305        $res_str .= "find \"$arg1\" in \"$arg0\" - grapheme_strripos";
306        if ( 3 == count( $test ) ) {
307            $result = grapheme_strripos($test[0], $test[1]);
308        }
309        else {
310            $res_str .= " from $test[2]";
311            $result = grapheme_strripos($test[0], $test[1], $test[2]);
312        }
313        $res_str .= " = ";
314        if ( $result === false ) {
315            $res_str .= 'false';
316        }
317        else {
318            $res_str .= $result;
319        }
320        $res_str .= " == " . $test[count($test)-1] . check_result($result, $test[count($test)-1]) . "\n";
321    }
322
323
324    //=====================================================================================
325    $res_str .= "\n" . 'function grapheme_substr($string, $start, $length = -1) {}' . "\n\n";
326
327    $tests = array(
328
329        array( "abc", 3, "" ),
330        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, 5, "" ),
331        array( "ao" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O", 2, $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O" ),
332        array( $char_o_diaeresis_nfd . $char_a_ring_nfd . "a" . $char_A_ring_nfd . "bc", 2, "a" . $char_A_ring_nfd . "bc" ),
333        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O", 5, "O" ),
334        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, 5, "" ),
335        array( "a" . $char_a_ring_nfd . "bc" . $char_O_diaeresis_nfd, 4, $char_O_diaeresis_nfd ),
336        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "bc", 2, $char_a_ring_nfd . "bc" ),
337        array( "a" . $char_A_ring_nfd . "bc", 1, $char_A_ring_nfd . "bc" ),
338        array( "Abc", -5, "Abc" ),
339        array( $char_a_ring_nfd . "bc", 3, "" ),
340        array( "abc", 4, "" ),
341        array( "abC", 2, "C" ),
342        array( "abc", 1, "bc" ),
343        array( "Abc", 1, 1, "b" ),
344        array( "abc", 0, 2, "ab" ),
345        array( "Abc", -4, 1, "A" ),
346        array( "ababc", 1, 2, "ba" ),
347        array( "ababc", 0, 10, "ababc" ),
348
349        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 0, 10 , "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq" ),
350        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 5, "Opq" ),
351        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 5, -1, "Op" ),
352        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 5, -2, "O" ),
353        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 5, -3, "" ),
354        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 5, -4, "" ),
355
356        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 0, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq" ),
357        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 0, -1, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Op" ),
358        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 0, -2, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O" ),
359        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 0, -3, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd ),
360        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 0, -4, "a" . $char_a_ring_nfd . "bc" ),
361        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 0, -5, "a" . $char_a_ring_nfd . "b" ),
362        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 0, -6, "a" . $char_a_ring_nfd ),
363        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 0, -7, "a" ),
364        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 0, -8, "" ),
365        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", 0, -9, "" ),
366
367        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq" ),
368        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -7, $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq" ),
369        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -6, "bc" . $char_o_diaeresis_nfd . "Opq" ),
370        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -5, "c" . $char_o_diaeresis_nfd . "Opq" ),
371        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -4, $char_o_diaeresis_nfd . "Opq" ),
372        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -3, "Opq" ),
373        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -2, "pq" ),
374        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -1, "q" ),
375        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -999, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq" ),
376
377        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, 8, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq" ),
378        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, 7, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Op" ),
379        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, 6, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O" ),
380        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, 5, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd ),
381        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, 4, "a" . $char_a_ring_nfd . "bc" ),
382        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, 3, "a" . $char_a_ring_nfd . "b" ),
383        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, 2, "a" . $char_a_ring_nfd ),
384        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, 1, "a" ),
385        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, 0, "" ),
386        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, -999, "" ),
387
388        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, -1, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Op" ),
389        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, -2, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O" ),
390        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, -3, "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd ),
391        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, -4, "a" . $char_a_ring_nfd . "bc" ),
392        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, -5, "a" . $char_a_ring_nfd . "b" ),
393        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, -6, "a" . $char_a_ring_nfd ),
394        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, -7, "a" ),
395        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, -8, "" ),
396        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "Opq", -8, -9, "" ),
397
398    );
399
400    foreach( $tests as $test ) {
401        try {
402            $arg0 = urlencode($test[0]);
403            $res_str .= "substring of \"$arg0\" from \"$test[1]\" - grapheme_substr";
404            if ( 3 == count( $test ) ) {
405                $result = grapheme_substr($test[0], $test[1]);
406            }
407            else {
408                $res_str .= " with length $test[2]";
409                $result = grapheme_substr($test[0], $test[1], $test[2]);
410            }
411            $res_str .= " = ";
412            if ( $result === false ) {
413                $res_str .= 'false';
414            }
415            else {
416                $res_str .= urlencode($result);
417            }
418            $res_str .= " == " . urlencode($test[count($test)-1]) . check_result($result, $test[count($test)-1]) . "\n";
419        } catch (ValueError $exception) {
420             $res_str .= ": " . $exception->getMessage() . "\n";
421        }
422    }
423
424
425    //=====================================================================================
426    $res_str .= "\n" . 'function grapheme_strstr($haystack, $needle, $before_needle = FALSE) {}' . "\n\n";
427
428    $tests = array(
429        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o", "o", "o" ),
430        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "o", "false" ),
431        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, $char_o_diaeresis_nfd, $char_o_diaeresis_nfd ),
432        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, $char_a_ring_nfd . "bc"),
433        array( "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, $char_a_ring_nfd . "bc"),
434        array( "abc", $char_a_ring_nfd, "false" ),
435        array( $char_a_ring_nfd . "bc", "a", "false" ),
436        array( "abc", "d", "false" ),
437        array( "abc", "c", "c" ),
438        array( "abc", "b", "bc" ),
439        array( "abc", "a", "abc" ),
440        array( "abc", "ab", "abc" ),
441        array( "abc", "abc", "abc" ),
442        array( "abc", "bc", "bc" ),
443        array( "abc", "a", FALSE, "abc" ),
444        array( "abc", "a", TRUE, "" ),
445        array( "abc", "b", TRUE, "a" ),
446        array( "abc", "c", TRUE, "ab" ),
447        array( "ababc", "bab", TRUE, "a" ),
448        array( "ababc", "abc", TRUE, "ab" ),
449        array( "ababc", "abc", FALSE, "abc" ),
450
451        array( "ab" . $char_a_ring_nfd . "c", "d", "false" ),
452        array( "bc" . $char_a_ring_nfd . "a", "a", "a" ),
453        array( "a" . $char_a_ring_nfd . "bc", "b", "bc" ),
454        array( $char_a_ring_nfd . "bc", "a", "false" ),
455        array( $char_a_ring_nfd . "abc", "ab", "abc" ),
456        array( "abc" . $char_a_ring_nfd, "abc", "abc" . $char_a_ring_nfd),
457        array( "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd . "bc", $char_a_ring_nfd . "bc" ),
458        array( "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, FALSE, $char_a_ring_nfd . "bc"),
459        array( "a" . $char_a_ring_nfd . "bc", "a", TRUE, "" ),
460        array( $char_a_ring_nfd . "abc", "b", TRUE, $char_a_ring_nfd . "a" ),
461        array( "ab" . $char_a_ring_nfd . "c", "c", TRUE, "ab" . $char_a_ring_nfd ),
462        array( "aba" . $char_a_ring_nfd . "bc", "ba" . $char_a_ring_nfd . "b", TRUE, "a" ),
463        array( "ababc" . $char_a_ring_nfd, "abc" . $char_a_ring_nfd, TRUE, "ab" ),
464        array( "abab" . $char_a_ring_nfd . "c", "ab" . $char_a_ring_nfd . "c", FALSE, "ab" . $char_a_ring_nfd . "c" ),
465
466    );
467
468    foreach( $tests as $test ) {
469        $arg1 = urlencode($test[1]);
470        $arg0 = urlencode($test[0]);
471        $res_str .= "find \"$arg1\" in \"$arg0\" - grapheme_strstr";
472        if ( 3 == count( $test ) ) {
473            $result = grapheme_strstr($test[0], $test[1]);
474        }
475        else {
476            $res_str .= " before flag is " . ( $test[2] ? "TRUE" : "FALSE" );
477            $result = grapheme_strstr($test[0], $test[1], $test[2]);
478        }
479        $res_str .= " = ";
480        if ( $result === false ) {
481            $res_str .= 'false';
482        }
483        else {
484            $res_str .= urlencode($result);
485        }
486        $res_str .= " == " . urlencode($test[count($test)-1]) . check_result($result, $test[count($test)-1]) . "\n";
487    }
488
489
490    //=====================================================================================
491    $res_str .= "\n" . 'function grapheme_stristr($haystack, $needle, $before_needle = FALSE) {}' . "\n\n";
492
493    $tests = array(
494        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, $char_O_diaeresis_nfd, $char_o_diaeresis_nfd ),
495        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O", "o", "O" ),
496        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "o", "false" ),
497        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, $char_a_ring_nfd . "bc"),
498        array( "a" . $char_a_ring_nfd . "bc", $char_A_ring_nfd, $char_a_ring_nfd . "bc"),
499        array( "abc", $char_a_ring_nfd, "false" ),
500        array( $char_a_ring_nfd . "bc", "A", "false" ),
501        array( "abc", "d", "false" ),
502        array( "abc", "C", "c" ),
503        array( "aBc", "b", "Bc" ),
504        array( "abc", "A", "abc" ),
505        array( "abC", "ab", "abC" ),
506        array( "abc", "aBc", "abc" ),
507        array( "abC", "bc", "bC" ),
508        array( "abc", "A", FALSE, "abc" ),
509        array( "abc", "a", TRUE, "" ),
510        array( "aBc", "b", TRUE, "a" ),
511        array( "abc", "C", TRUE, "ab" ),
512        array( "aBabc", "bab", TRUE, "a" ),
513        array( "ababc", "aBc", TRUE, "ab" ),
514        array( "ababc", "abC", FALSE, "abc" ),
515
516        array( "ab" . $char_a_ring_nfd . "c", "d", "false" ),
517        array( "bc" . $char_a_ring_nfd . "A", "a", "A" ),
518        array( "a" . $char_a_ring_nfd . "bc", "B", "bc" ),
519        array( $char_A_ring_nfd . "bc", "a", "false" ),
520        array( $char_a_ring_nfd . "abc", "Ab", "abc" ),
521        array( "abc" . $char_A_ring_nfd, "abc", "abc" . $char_A_ring_nfd),
522        array( "a" . $char_a_ring_nfd . "bc", $char_A_ring_nfd . "bc", $char_a_ring_nfd . "bc" ),
523        array( "a" . $char_A_ring_nfd . "bc", $char_a_ring_nfd, FALSE, $char_A_ring_nfd . "bc" ),
524        array( "a" . $char_a_ring_nfd . "bc", "A", TRUE, "" ),
525        array( $char_a_ring_nfd . "aBc", "b", TRUE, $char_a_ring_nfd . "a" ),
526        array( "ab" . $char_a_ring_nfd . "c", "C", TRUE, "ab" . $char_a_ring_nfd ),
527        array( "aba" . $char_A_ring_nfd . "bc", "ba" . $char_a_ring_nfd . "b", TRUE, "a" ),
528        array( "ababc" . $char_a_ring_nfd, "aBc" . $char_A_ring_nfd, TRUE, "ab" ),
529        array( "abAB" . $char_A_ring_nfd . "c", "ab" . $char_a_ring_nfd . "c", FALSE, "AB" . $char_A_ring_nfd . "c" ),
530
531    );
532
533    foreach( $tests as $test ) {
534        $arg1 = urlencode($test[1]);
535        $arg0 = urlencode($test[0]);
536        $res_str .= "find \"$arg1\" in \"$arg0\" - grapheme_stristr";
537        if ( 3 == count( $test ) ) {
538            $result = grapheme_stristr($test[0], $test[1]);
539        }
540        else {
541            $res_str .= " before flag is " . ( $test[2] ? "TRUE" : "FALSE" );
542            $result = grapheme_stristr($test[0], $test[1], $test[2]);
543        }
544        $res_str .= " = ";
545        if ( $result === false ) {
546            $res_str .= 'false';
547        }
548        else {
549            $res_str .= urlencode($result);
550        }
551        $res_str .= " == " . urlencode($test[count($test)-1]) . check_result($result, $test[count($test)-1]) . "\n";
552    }
553
554
555    //=====================================================================================
556    $res_str .= "\n" . 'function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_COUNT, $start = 0[, $next])' . "\n\n";
557
558    $tests = array(
559        // haystack, count, [[offset], [next]], result
560        array( "abc", 3, "abc" ),
561        array( "abc", 2, "ab" ),
562        array( "abc", 1, "a" ),
563        array( "abc", 0, "" ),
564        array( "abc", 1, 0, "a" ),
565        array( "abc", 1, 1, "b" ),
566        array( "abc", 1, 2, "c" ),
567        array( "abc", 0, 2, "" ),
568
569        array( "abc", 3, 0, 3, "abc" ),
570        array( "abc", 2, 0, 2, "ab" ),
571        array( "abc", 1, 0, 1, "a" ),
572        array( "abc", 0, 0, 0, "" ),
573        array( "abc", 1, 0, 1, "a" ),
574        array( "abc", 1, 1, 2, "b" ),
575        array( "abc", 1, 2, 3, "c" ),
576        array( "abc", 1, -2, 2, "b" ),
577        array( "abc", 0, 2, 2, "" ),
578        array( "http://news.bbc.co.uk/2/hi/middle_east/7831588.stm", 48, 48 , 50 , "tm" ),
579
580        array( $char_a_ring_nfd . "bc", 3, $char_a_ring_nfd . "bc" ),
581        array( $char_a_ring_nfd . "bc", 2, $char_a_ring_nfd . "b" ),
582        array( $char_a_ring_nfd . "bc", 1, $char_a_ring_nfd . "" ),
583        array( $char_a_ring_nfd . "bc", 3, 0, 5, $char_a_ring_nfd . "bc" ),
584        array( $char_a_ring_nfd . "bc", 2, 0, 4, $char_a_ring_nfd . "b" ),
585        array( $char_a_ring_nfd . "bc", 1, 0, 3, $char_a_ring_nfd . "" ),
586        array( $char_a_ring_nfd . "bcde", 2, 3, 5, "bc" ),
587        array( $char_a_ring_nfd . "bcde", 2, -4, 5, "bc" ),
588        array( $char_a_ring_nfd . "bcde", 2, 4, 6, "cd" ),
589        array( $char_a_ring_nfd . "bcde", 2, -7, 4, $char_a_ring_nfd . "b" ),
590        array( $char_a_ring_nfd . "bcde" . $char_a_ring_nfd . "f", 4, 5, 11, "de" . $char_a_ring_nfd . "f" ),
591        array( $char_a_ring_nfd . "bcde" . $char_a_ring_nfd . "f", 4, -6, 11, "de" . $char_a_ring_nfd . "f" ),
592
593        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 3, $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd ),
594        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, $char_a_ring_nfd . $char_o_diaeresis_nfd ),
595        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . "c", 1, $char_a_ring_nfd . "" ),
596
597        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 1, 0, $char_o_diaeresis_nfd),
598        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 1, 2, $char_o_diaeresis_nfd),
599        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 1, 3, $char_o_diaeresis_nfd),
600        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 1, 4, $char_diaeresis),
601
602        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 0, $char_o_diaeresis_nfd . $char_o_diaeresis_nfd),
603        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 2, $char_o_diaeresis_nfd . $char_o_diaeresis_nfd),
604        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 3, $char_o_diaeresis_nfd . $char_o_diaeresis_nfd),
605        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 4, $char_diaeresis . $char_o_diaeresis_nfd),
606        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 7, $char_diaeresis . $char_o_diaeresis_nfd),
607        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 8, $char_o_diaeresis_nfd),
608        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 10, $char_diaeresis),
609        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 11, "false"),
610
611    );
612
613    $next = -1;
614    foreach( $tests as $test ) {
615        $arg0 = urlencode($test[0]);
616        $res_str .= "extract from \"$arg0\" \"$test[1]\" graphemes - grapheme_extract";
617        if ( 3 == count( $test ) ) {
618            $result = grapheme_extract($test[0], $test[1]);
619        }
620        elseif ( 4 == count ( $test ) ) {
621            $res_str .= " starting at byte position $test[2]";
622            $result = grapheme_extract($test[0], $test[1], GRAPHEME_EXTR_COUNT, $test[2]);
623        }
624        else {
625            $res_str .= " starting at byte position $test[2] with \$next";
626            $result = grapheme_extract($test[0], $test[1], GRAPHEME_EXTR_COUNT, $test[2], $next);
627        }
628        $res_str .= " = ";
629        if ( $result === false ) {
630            $res_str .= 'false';
631        }
632        else {
633            $res_str .= urlencode($result);
634        }
635        $res_str .= " == " . urlencode($test[count($test)-1]) . check_result($result, $test[count($test)-1]);
636        if ( 5 == count ( $test ) ) {
637            $res_str .= " \$next=$next == $test[3] ";
638            if ( $next != $test[3] ) {
639                $res_str .= "***FAILED***";
640            }
641        }
642        $res_str .= "\n";
643    }
644
645
646    //=====================================================================================
647    $res_str .= "\n" . 'function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_MAXBYTES, $start = 0)' . "\n\n";
648
649    $tests = array(
650        array( "abc", 3, "abc" ),
651        array( "abc", 2, "ab" ),
652        array( "abc", 1, "a" ),
653        array( "abc", 0, "" ),
654        array( $char_a_ring_nfd . "bc", 5, $char_a_ring_nfd . "bc" ),
655        array( $char_a_ring_nfd . "bc", 4, $char_a_ring_nfd . "b" ),
656        array( $char_a_ring_nfd . "bc", 1, "" ),
657        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 9, $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd ),
658        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 10, $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd ),
659        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 11, $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd ),
660        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 6, $char_a_ring_nfd . $char_o_diaeresis_nfd ),
661        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . "c", 3, $char_a_ring_nfd . "" ),
662        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . "c", 4, $char_a_ring_nfd . "" ),
663        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . "c", 5, $char_a_ring_nfd . "" ),
664        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . "c", 6, $char_a_ring_nfd . $char_o_diaeresis_nfd  ),
665        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . "c", 7, $char_a_ring_nfd . $char_o_diaeresis_nfd . "c" ),
666
667        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 3, 0, $char_o_diaeresis_nfd),
668        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 3, 2, $char_o_diaeresis_nfd),
669        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 3, 3, $char_o_diaeresis_nfd),
670        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 3, 4, $char_diaeresis),
671
672        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 6, 0, $char_o_diaeresis_nfd . $char_o_diaeresis_nfd),
673        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 6, 2, $char_o_diaeresis_nfd . $char_o_diaeresis_nfd),
674        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 6, 3, $char_o_diaeresis_nfd . $char_o_diaeresis_nfd),
675        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 5, 4, $char_diaeresis . $char_o_diaeresis_nfd),
676        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 5, 7, $char_diaeresis . $char_o_diaeresis_nfd),
677        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 3, 8, $char_o_diaeresis_nfd),
678        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 10, $char_diaeresis),
679        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 11, "false"),
680
681    );
682
683    foreach( $tests as $test ) {
684        $arg0 = urlencode($test[0]);
685        $res_str .= "extract from \"$arg0\" \"$test[1]\" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES";
686        if ( 3 == count( $test ) ) {
687            $result = grapheme_extract($test[0], $test[1], GRAPHEME_EXTR_MAXBYTES);
688        }
689        else {
690            $res_str .= " starting at byte position $test[2]";
691            $result = grapheme_extract($test[0], $test[1], GRAPHEME_EXTR_MAXBYTES, $test[2]);
692        }
693        $res_str .= " = ";
694        if ( $result === false ) {
695            $res_str .= 'false';
696        }
697        else {
698            $res_str .= urlencode($result);
699        }
700        $res_str .= " == " . urlencode($test[count($test)-1]) . check_result($result, $test[count($test)-1]) . "\n";
701    }
702
703
704    //=====================================================================================
705    $res_str .= "\n" . 'function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_MAXCHARS, $start = 0)' . "\n\n";
706
707    $tests = array(
708        array( "abc", 3, "abc" ),
709        array( "abc", 2, "ab" ),
710        array( "abc", 1, "a" ),
711        array( "abc", 0, "" ),
712        array( "abc" . $char_o_diaeresis_nfd, 0, "" ),
713        array( "abc" . $char_o_diaeresis_nfd, 1, "a" ),
714        array( "abc" . $char_o_diaeresis_nfd, 2, "ab" ),
715        array( "abc" . $char_o_diaeresis_nfd, 3, "abc" ),
716        array( "abc" . $char_o_diaeresis_nfd, 4, "abc" ),
717        array( "abc" . $char_o_diaeresis_nfd, 5, "abc" . $char_o_diaeresis_nfd),
718        array( "abc" . $char_o_diaeresis_nfd, 6, "abc" . $char_o_diaeresis_nfd),
719        array( $char_o_diaeresis_nfd . "abc", 0, "" ),
720        array( $char_o_diaeresis_nfd . "abc", 1, "" ),
721        array( $char_o_diaeresis_nfd . "abc", 2, $char_o_diaeresis_nfd ),
722        array( $char_o_diaeresis_nfd . "abc", 3, $char_o_diaeresis_nfd . "a" ),
723        array( $char_o_diaeresis_nfd . "abc", 4, $char_o_diaeresis_nfd . "ab" ),
724        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 5, $char_o_diaeresis_nfd . "abc" ),
725        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 6, $char_o_diaeresis_nfd . "abc" ),
726        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 7, $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd ),
727        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "x" ),
728
729        array( "abc", 3, 0, "abc" ),
730        array( "abc", 2, 1, "bc" ),
731        array( "abc", 1, 2, "c" ),
732        array( "abc", 0, 3, "false" ),
733        array( "abc", 1, 3, "false" ),
734        array( "abc", 1, 999, "false" ),
735        array( $char_o_diaeresis_nfd . "abc", 1, 6, "false" ),
736        array( $char_o_diaeresis_nfd . "abc", 1, 999, "false" ),
737        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 0, $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "x" ),
738        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 1, $char_diaeresis . "abc" . $char_a_ring_nfd . "xy" ),
739        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 2, "abc" . $char_a_ring_nfd . "xyz" ),
740        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 3, "abc" . $char_a_ring_nfd . "xyz" ),
741        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 4, "bc" . $char_a_ring_nfd . "xyz" ),
742        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 5, "c" . $char_a_ring_nfd . "xyz" ),
743        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 6, $char_a_ring_nfd . "xyz" ),
744
745    );
746
747    foreach( $tests as $test ) {
748        $arg0 = urlencode($test[0]);
749        $res_str .= "extract from \"$arg0\" \"$test[1]\" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS";
750        if ( 3 == count( $test ) ) {
751            $result = grapheme_extract($test[0], $test[1], GRAPHEME_EXTR_MAXCHARS);
752        }
753        else {
754            $res_str .= " starting at byte position $test[2]";
755            $result = grapheme_extract($test[0], $test[1], GRAPHEME_EXTR_MAXCHARS, $test[2]);
756        }
757        $res_str .= " = ";
758        if ( $result === false ) {
759            $res_str .= 'false';
760        }
761        else {
762            $res_str .= urlencode($result);
763        }
764        $res_str .= " == " . urlencode($test[count($test)-1]) . check_result($result, $test[count($test)-1]) . "\n";
765    }
766
767
768    //=====================================================================================
769
770    return $res_str;
771}
772
773echo ut_main();
774
775function check_result($result, $expected) {
776
777    if ( $result === false ) {
778            $result = 'false';
779    }
780
781    if ( strcmp($result, $expected) != 0 ) {
782        return " **FAILED** ";
783    }
784
785    return "";
786}
787
788?>
789--EXPECT--
790function grapheme_strlen($string) {}
791
792"hindi" in devanagari strlen 2
793"ab" + "hindi" + "cde" strlen 7
794"" strlen 0
795char_a_ring_nfd strlen 1
796char_a_ring_nfd + "bc" strlen 3
797"abc" strlen 3
798
799function grapheme_strpos($haystack, $needle, $offset = 0) {}
800
801find "o" in "aa%CC%8Abco%CC%88o" - grapheme_strpos = 5 == 5
802find "o" in "aa%CC%8Abco%CC%88" - grapheme_strpos = false == false
803find "o%CC%88" in "aa%CC%8Abco%CC%88" - grapheme_strpos = 4 == 4
804find "a%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_strpos = 2 == 2
805find "a%CC%8A" in "aa%CC%8Abc" - grapheme_strpos = 1 == 1
806find "a%CC%8A" in "abc" - grapheme_strpos = false == false
807find "a" in "a%CC%8Abc" - grapheme_strpos = false == false
808find "d" in "abc" - grapheme_strpos = false == false
809find "c" in "abc" - grapheme_strpos = 2 == 2
810find "b" in "abc" - grapheme_strpos = 1 == 1
811find "a" in "abc" - grapheme_strpos = 0 == 0
812find "a" in "abc" - grapheme_strpos from 0 = 0 == 0
813find "a" in "abc" - grapheme_strpos from 1 = false == false
814find "a" in "abc" - grapheme_strpos from -1 = false == false
815find "a" in "ababc" - grapheme_strpos from 1 = 2 == 2
816find "o" in "aoa%CC%8Abco%CC%88o" - grapheme_strpos from 2 = 6 == 6
817find "o" in "aoa%CC%8Abco%CC%88o" - grapheme_strpos from -1 = 6 == 6
818find "o" in "aoa%CC%8Abco%CC%88o" - grapheme_strpos from -5 = 6 == 6
819find "a%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abc" - grapheme_strpos from 2 = 3 == 3
820find "a%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abc" - grapheme_strpos from -4 = 3 == 3
821find "op" in "aa%CC%8Abco%CC%88opq" - grapheme_strpos = 5 == 5
822find "opq" in "aa%CC%8Abco%CC%88opq" - grapheme_strpos = 5 == 5
823find "abc" in "aa%CC%8Abco%CC%88" - grapheme_strpos = false == false
824find "o%CC%88bco%CC%88" in "aa%CC%8Abco%CC%88bco%CC%88" - grapheme_strpos = 4 == 4
825find "a%CC%8Abc" in "o%CC%88aa%CC%8Abc" - grapheme_strpos = 2 == 2
826find "a%CC%8Abc" in "aa%CC%8Abc" - grapheme_strpos = 1 == 1
827find "a%CC%8Abc" in "abc" - grapheme_strpos = false == false
828find "abcdefg" in "a%CC%8Abc" - grapheme_strpos = false == false
829find "defghijklmnopq" in "abc" - grapheme_strpos = false == false
830find "ab" in "abc" - grapheme_strpos = 0 == 0
831find "bc" in "abc" - grapheme_strpos = 1 == 1
832find "abc" in "abc" - grapheme_strpos = 0 == 0
833find "abcd" in "abc" - grapheme_strpos = false == false
834find "ab" in "abc" - grapheme_strpos from 0 = 0 == 0
835find "abc" in "abc" - grapheme_strpos from 0 = 0 == 0
836find "abc" in "abc" - grapheme_strpos from 1 = false == false
837find "ab" in "ababc" - grapheme_strpos from 1 = 2 == 2
838find "abc" in "ababc" - grapheme_strpos from 1 = 2 == 2
839find "oa%CC%8Abc" in "aoa%CC%8Abco%CC%88oa%CC%8Abc" - grapheme_strpos from 2 = 6 == 6
840find "oa%CC%8Abc" in "aoa%CC%8Abco%CC%88oa%CC%8Abc" - grapheme_strpos from -8 = 6 == 6
841find "a%CC%8Abca%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abca%CC%8Adef" - grapheme_strpos from 2 = 3 == 3
842
843function grapheme_stripos($haystack, $needle, $offset = 0) {}
844
845find "o" in "aoa%CC%8Abco%CC%88O" - grapheme_stripos from 2 = 6 == 6
846find "o" in "aoa%CC%8Abco%CC%88Oo" - grapheme_stripos from -6 = 6 == 6
847find "a%CC%8A" in "o%CC%88a%CC%8AaA%CC%8Abc" - grapheme_stripos from 2 = 3 == 3
848find "o" in "aa%CC%8Abco%CC%88O" - grapheme_stripos = 5 == 5
849find "O" in "aa%CC%8Abco%CC%88" - grapheme_stripos = false == false
850find "o%CC%88" in "aa%CC%8AbcO%CC%88" - grapheme_stripos = 4 == 4
851find "o%CC%88" in "aa%CC%8AbcO%CC%88" - grapheme_stripos from -1 = 4 == 4
852find "A%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_stripos = 2 == 2
853find "a%CC%8A" in "aA%CC%8Abc" - grapheme_stripos = 1 == 1
854find "a%CC%8A" in "Abc" - grapheme_stripos = false == false
855find "A" in "a%CC%8Abc" - grapheme_stripos = false == false
856find "D" in "abc" - grapheme_stripos = false == false
857find "c" in "abC" - grapheme_stripos = 2 == 2
858find "B" in "abc" - grapheme_stripos = 1 == 1
859find "a" in "Abc" - grapheme_stripos = 0 == 0
860find "A" in "abc" - grapheme_stripos from 0 = 0 == 0
861find "a" in "Abc" - grapheme_stripos from 1 = false == false
862find "A" in "ababc" - grapheme_stripos from 1 = 2 == 2
863find "oP" in "aa%CC%8Abco%CC%88Opq" - grapheme_stripos = 5 == 5
864find "opQ" in "aa%CC%8Abco%CC%88Opq" - grapheme_stripos = 5 == 5
865find "abc" in "aa%CC%8Abco%CC%88" - grapheme_stripos = false == false
866find "O%CC%88bco%CC%88" in "aa%CC%8Abco%CC%88bCo%CC%88" - grapheme_stripos = 4 == 4
867find "A%CC%8Abc" in "o%CC%88aa%CC%8ABc" - grapheme_stripos = 2 == 2
868find "a%CC%8Abc" in "aa%CC%8ABC" - grapheme_stripos = 1 == 1
869find "a%CC%8ABC" in "abc" - grapheme_stripos = false == false
870find "aBCdefg" in "a%CC%8ABC" - grapheme_stripos = false == false
871find "Defghijklmnopq" in "aBC" - grapheme_stripos = false == false
872find "Ab" in "abC" - grapheme_stripos = 0 == 0
873find "bc" in "aBC" - grapheme_stripos = 1 == 1
874find "Abc" in "abC" - grapheme_stripos = 0 == 0
875find "aBcd" in "abC" - grapheme_stripos = false == false
876find "ab" in "ABc" - grapheme_stripos from 0 = 0 == 0
877find "abC" in "aBc" - grapheme_stripos from 0 = 0 == 0
878find "aBc" in "abc" - grapheme_stripos from 1 = false == false
879find "AB" in "ABabc" - grapheme_stripos from 1 = 2 == 2
880find "AB" in "ABabc" - grapheme_stripos from -4 = 2 == 2
881find "aBc" in "abaBc" - grapheme_stripos from 1 = 2 == 2
882find "Oa%CC%8AbC" in "aoa%CC%8Abco%CC%88oA%CC%8AbC" - grapheme_stripos from 2 = 6 == 6
883find "a%CC%8ABca%CC%8A" in "o%CC%88a%CC%8AaA%CC%8AbCa%CC%8Adef" - grapheme_stripos from 2 = 3 == 3
884
885function grapheme_strrpos($haystack, $needle, $offset = 0) {}
886
887find "o" in "aa%CC%8Abco%CC%88o" - grapheme_strrpos = 5 == 5
888find "o" in "aa%CC%8Abco%CC%88" - grapheme_strrpos = false == false
889find "o%CC%88" in "aa%CC%8Abco%CC%88" - grapheme_strrpos = 4 == 4
890find "a%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_strrpos = 2 == 2
891find "a%CC%8A" in "aa%CC%8Abc" - grapheme_strrpos = 1 == 1
892find "a%CC%8A" in "abc" - grapheme_strrpos = false == false
893find "a" in "a%CC%8Abc" - grapheme_strrpos = false == false
894find "d" in "abc" - grapheme_strrpos = false == false
895find "c" in "abc" - grapheme_strrpos = 2 == 2
896find "b" in "abc" - grapheme_strrpos = 1 == 1
897find "a" in "abc" - grapheme_strrpos = 0 == 0
898find "a" in "abc" - grapheme_strrpos from 0 = 0 == 0
899find "a" in "abc" - grapheme_strrpos from 1 = false == false
900find "a" in "ababc" - grapheme_strrpos from 1 = 2 == 2
901find "o" in "aoa%CC%8Abco%CC%88o" - grapheme_strrpos from 2 = 6 == 6
902find "a%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abc" - grapheme_strrpos from 2 = 3 == 3
903find "op" in "aa%CC%8Abco%CC%88opq" - grapheme_strrpos = 5 == 5
904find "opq" in "aa%CC%8Abco%CC%88opq" - grapheme_strrpos = 5 == 5
905find "abc" in "aa%CC%8Abco%CC%88" - grapheme_strrpos = false == false
906find "o%CC%88bco%CC%88" in "aa%CC%8Abco%CC%88bco%CC%88" - grapheme_strrpos = 4 == 4
907find "a%CC%8Abc" in "o%CC%88aa%CC%8Abc" - grapheme_strrpos = 2 == 2
908find "a%CC%8Abc" in "aa%CC%8Abc" - grapheme_strrpos = 1 == 1
909find "a%CC%8Abc" in "abc" - grapheme_strrpos = false == false
910find "abcdefg" in "a%CC%8Abc" - grapheme_strrpos = false == false
911find "defghijklmnopq" in "abc" - grapheme_strrpos = false == false
912find "ab" in "abc" - grapheme_strrpos = 0 == 0
913find "bc" in "abc" - grapheme_strrpos = 1 == 1
914find "abc" in "abc" - grapheme_strrpos = 0 == 0
915find "abcd" in "abc" - grapheme_strrpos = false == false
916find "ab" in "abc" - grapheme_strrpos from 0 = 0 == 0
917find "abc" in "abc" - grapheme_strrpos from 0 = 0 == 0
918find "abc" in "abc" - grapheme_strrpos from 1 = false == false
919find "ab" in "ababc" - grapheme_strrpos from 1 = 2 == 2
920find "abc" in "ababc" - grapheme_strrpos from 1 = 2 == 2
921find "oa%CC%8Abc" in "aoa%CC%8Abco%CC%88oa%CC%8Abc" - grapheme_strrpos from 2 = 6 == 6
922find "a%CC%8Abca%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abca%CC%8Adef" - grapheme_strrpos from 2 = 3 == 3
923
924function grapheme_strripos($haystack, $needle, $offset = 0) {}
925
926find "o" in "aoa%CC%8Abco%CC%88O" - grapheme_strripos from 2 = 6 == 6
927find "a%CC%8A" in "o%CC%88a%CC%8AaA%CC%8Abc" - grapheme_strripos from 2 = 3 == 3
928find "o" in "aa%CC%8Abco%CC%88O" - grapheme_strripos = 5 == 5
929find "O" in "aa%CC%8Abco%CC%88" - grapheme_strripos = false == false
930find "o%CC%88" in "aa%CC%8AbcO%CC%88" - grapheme_strripos = 4 == 4
931find "A%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_strripos = 2 == 2
932find "a%CC%8A" in "aA%CC%8Abc" - grapheme_strripos = 1 == 1
933find "a%CC%8A" in "Abc" - grapheme_strripos = false == false
934find "A" in "a%CC%8Abc" - grapheme_strripos = false == false
935find "D" in "abc" - grapheme_strripos = false == false
936find "c" in "abC" - grapheme_strripos = 2 == 2
937find "B" in "abc" - grapheme_strripos = 1 == 1
938find "a" in "Abc" - grapheme_strripos = 0 == 0
939find "A" in "abc" - grapheme_strripos from 0 = 0 == 0
940find "a" in "Abc" - grapheme_strripos from 1 = false == false
941find "A" in "ababc" - grapheme_strripos from 1 = 2 == 2
942find "oP" in "aa%CC%8Abco%CC%88Opq" - grapheme_strripos = 5 == 5
943find "opQ" in "aa%CC%8Abco%CC%88Opq" - grapheme_strripos = 5 == 5
944find "abc" in "aa%CC%8Abco%CC%88" - grapheme_strripos = false == false
945find "O%CC%88bco%CC%88" in "aa%CC%8Abco%CC%88bCo%CC%88" - grapheme_strripos = 4 == 4
946find "A%CC%8Abc" in "o%CC%88aa%CC%8ABc" - grapheme_strripos = 2 == 2
947find "a%CC%8Abc" in "aa%CC%8ABC" - grapheme_strripos = 1 == 1
948find "a%CC%8ABC" in "abc" - grapheme_strripos = false == false
949find "aBCdefg" in "a%CC%8ABC" - grapheme_strripos = false == false
950find "Defghijklmnopq" in "aBC" - grapheme_strripos = false == false
951find "Ab" in "abC" - grapheme_strripos = 0 == 0
952find "bc" in "aBC" - grapheme_strripos = 1 == 1
953find "Abc" in "abC" - grapheme_strripos = 0 == 0
954find "aBcd" in "abC" - grapheme_strripos = false == false
955find "ab" in "ABc" - grapheme_strripos from 0 = 0 == 0
956find "abC" in "aBc" - grapheme_strripos from 0 = 0 == 0
957find "aBc" in "abc" - grapheme_strripos from 1 = false == false
958find "AB" in "ABabc" - grapheme_strripos from 1 = 2 == 2
959find "aBc" in "abaBc" - grapheme_strripos from 1 = 2 == 2
960find "Oa%CC%8AbC" in "aoa%CC%8Abco%CC%88oA%CC%8AbC" - grapheme_strripos from 2 = 6 == 6
961find "a%CC%8ABca%CC%8A" in "o%CC%88a%CC%8AaA%CC%8AbCa%CC%8Adef" - grapheme_strripos from 2 = 3 == 3
962
963function grapheme_substr($string, $start, $length = -1) {}
964
965substring of "abc" from "3" - grapheme_substr =  ==
966substring of "aa%CC%8Abco%CC%88" from "5" - grapheme_substr =  ==
967substring of "aoa%CC%8Abco%CC%88O" from "2" - grapheme_substr = a%CC%8Abco%CC%88O == a%CC%8Abco%CC%88O
968substring of "o%CC%88a%CC%8AaA%CC%8Abc" from "2" - grapheme_substr = aA%CC%8Abc == aA%CC%8Abc
969substring of "aa%CC%8Abco%CC%88O" from "5" - grapheme_substr = O == O
970substring of "aa%CC%8Abco%CC%88" from "5" - grapheme_substr =  ==
971substring of "aa%CC%8AbcO%CC%88" from "4" - grapheme_substr = O%CC%88 == O%CC%88
972substring of "o%CC%88aa%CC%8Abc" from "2" - grapheme_substr = a%CC%8Abc == a%CC%8Abc
973substring of "aA%CC%8Abc" from "1" - grapheme_substr = A%CC%8Abc == A%CC%8Abc
974substring of "Abc" from "-5" - grapheme_substr = Abc == Abc
975substring of "a%CC%8Abc" from "3" - grapheme_substr =  ==
976substring of "abc" from "4" - grapheme_substr =  ==
977substring of "abC" from "2" - grapheme_substr = C == C
978substring of "abc" from "1" - grapheme_substr = bc == bc
979substring of "Abc" from "1" - grapheme_substr with length 1 = b == b
980substring of "abc" from "0" - grapheme_substr with length 2 = ab == ab
981substring of "Abc" from "-4" - grapheme_substr with length 1 = A == A
982substring of "ababc" from "1" - grapheme_substr with length 2 = ba == ba
983substring of "ababc" from "0" - grapheme_substr with length 10 = ababc == ababc
984substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length 10 = aa%CC%8Abco%CC%88Opq == aa%CC%8Abco%CC%88Opq
985substring of "aa%CC%8Abco%CC%88Opq" from "5" - grapheme_substr = Opq == Opq
986substring of "aa%CC%8Abco%CC%88Opq" from "5" - grapheme_substr with length -1 = Op == Op
987substring of "aa%CC%8Abco%CC%88Opq" from "5" - grapheme_substr with length -2 = O == O
988substring of "aa%CC%8Abco%CC%88Opq" from "5" - grapheme_substr with length -3 =  ==
989substring of "aa%CC%8Abco%CC%88Opq" from "5" - grapheme_substr with length -4 =  ==
990substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr = aa%CC%8Abco%CC%88Opq == aa%CC%8Abco%CC%88Opq
991substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -1 = aa%CC%8Abco%CC%88Op == aa%CC%8Abco%CC%88Op
992substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -2 = aa%CC%8Abco%CC%88O == aa%CC%8Abco%CC%88O
993substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -3 = aa%CC%8Abco%CC%88 == aa%CC%8Abco%CC%88
994substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -4 = aa%CC%8Abc == aa%CC%8Abc
995substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -5 = aa%CC%8Ab == aa%CC%8Ab
996substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -6 = aa%CC%8A == aa%CC%8A
997substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -7 = a == a
998substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -8 =  ==
999substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -9 =  ==
1000substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr = aa%CC%8Abco%CC%88Opq == aa%CC%8Abco%CC%88Opq
1001substring of "aa%CC%8Abco%CC%88Opq" from "-7" - grapheme_substr = a%CC%8Abco%CC%88Opq == a%CC%8Abco%CC%88Opq
1002substring of "aa%CC%8Abco%CC%88Opq" from "-6" - grapheme_substr = bco%CC%88Opq == bco%CC%88Opq
1003substring of "aa%CC%8Abco%CC%88Opq" from "-5" - grapheme_substr = co%CC%88Opq == co%CC%88Opq
1004substring of "aa%CC%8Abco%CC%88Opq" from "-4" - grapheme_substr = o%CC%88Opq == o%CC%88Opq
1005substring of "aa%CC%8Abco%CC%88Opq" from "-3" - grapheme_substr = Opq == Opq
1006substring of "aa%CC%8Abco%CC%88Opq" from "-2" - grapheme_substr = pq == pq
1007substring of "aa%CC%8Abco%CC%88Opq" from "-1" - grapheme_substr = q == q
1008substring of "aa%CC%8Abco%CC%88Opq" from "-999" - grapheme_substr = aa%CC%8Abco%CC%88Opq == aa%CC%8Abco%CC%88Opq
1009substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 8 = aa%CC%8Abco%CC%88Opq == aa%CC%8Abco%CC%88Opq
1010substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 7 = aa%CC%8Abco%CC%88Op == aa%CC%8Abco%CC%88Op
1011substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 6 = aa%CC%8Abco%CC%88O == aa%CC%8Abco%CC%88O
1012substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 5 = aa%CC%8Abco%CC%88 == aa%CC%8Abco%CC%88
1013substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 4 = aa%CC%8Abc == aa%CC%8Abc
1014substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 3 = aa%CC%8Ab == aa%CC%8Ab
1015substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 2 = aa%CC%8A == aa%CC%8A
1016substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 1 = a == a
1017substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 0 =  ==
1018substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -999 =  ==
1019substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -1 = aa%CC%8Abco%CC%88Op == aa%CC%8Abco%CC%88Op
1020substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -2 = aa%CC%8Abco%CC%88O == aa%CC%8Abco%CC%88O
1021substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -3 = aa%CC%8Abco%CC%88 == aa%CC%8Abco%CC%88
1022substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -4 = aa%CC%8Abc == aa%CC%8Abc
1023substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -5 = aa%CC%8Ab == aa%CC%8Ab
1024substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -6 = aa%CC%8A == aa%CC%8A
1025substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -7 = a == a
1026substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -8 =  ==
1027substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -9 =  ==
1028
1029function grapheme_strstr($haystack, $needle, $before_needle = FALSE) {}
1030
1031find "o" in "aa%CC%8Abco%CC%88o" - grapheme_strstr = o == o
1032find "o" in "aa%CC%8Abco%CC%88" - grapheme_strstr = false == false
1033find "o%CC%88" in "aa%CC%8Abco%CC%88" - grapheme_strstr = o%CC%88 == o%CC%88
1034find "a%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_strstr = a%CC%8Abc == a%CC%8Abc
1035find "a%CC%8A" in "aa%CC%8Abc" - grapheme_strstr = a%CC%8Abc == a%CC%8Abc
1036find "a%CC%8A" in "abc" - grapheme_strstr = false == false
1037find "a" in "a%CC%8Abc" - grapheme_strstr = false == false
1038find "d" in "abc" - grapheme_strstr = false == false
1039find "c" in "abc" - grapheme_strstr = c == c
1040find "b" in "abc" - grapheme_strstr = bc == bc
1041find "a" in "abc" - grapheme_strstr = abc == abc
1042find "ab" in "abc" - grapheme_strstr = abc == abc
1043find "abc" in "abc" - grapheme_strstr = abc == abc
1044find "bc" in "abc" - grapheme_strstr = bc == bc
1045find "a" in "abc" - grapheme_strstr before flag is FALSE = abc == abc
1046find "a" in "abc" - grapheme_strstr before flag is TRUE =  ==
1047find "b" in "abc" - grapheme_strstr before flag is TRUE = a == a
1048find "c" in "abc" - grapheme_strstr before flag is TRUE = ab == ab
1049find "bab" in "ababc" - grapheme_strstr before flag is TRUE = a == a
1050find "abc" in "ababc" - grapheme_strstr before flag is TRUE = ab == ab
1051find "abc" in "ababc" - grapheme_strstr before flag is FALSE = abc == abc
1052find "d" in "aba%CC%8Ac" - grapheme_strstr = false == false
1053find "a" in "bca%CC%8Aa" - grapheme_strstr = a == a
1054find "b" in "aa%CC%8Abc" - grapheme_strstr = bc == bc
1055find "a" in "a%CC%8Abc" - grapheme_strstr = false == false
1056find "ab" in "a%CC%8Aabc" - grapheme_strstr = abc == abc
1057find "abc" in "abca%CC%8A" - grapheme_strstr = abca%CC%8A == abca%CC%8A
1058find "a%CC%8Abc" in "aa%CC%8Abc" - grapheme_strstr = a%CC%8Abc == a%CC%8Abc
1059find "a%CC%8A" in "aa%CC%8Abc" - grapheme_strstr before flag is FALSE = a%CC%8Abc == a%CC%8Abc
1060find "a" in "aa%CC%8Abc" - grapheme_strstr before flag is TRUE =  ==
1061find "b" in "a%CC%8Aabc" - grapheme_strstr before flag is TRUE = a%CC%8Aa == a%CC%8Aa
1062find "c" in "aba%CC%8Ac" - grapheme_strstr before flag is TRUE = aba%CC%8A == aba%CC%8A
1063find "baa%CC%8Ab" in "abaa%CC%8Abc" - grapheme_strstr before flag is TRUE = a == a
1064find "abca%CC%8A" in "ababca%CC%8A" - grapheme_strstr before flag is TRUE = ab == ab
1065find "aba%CC%8Ac" in "ababa%CC%8Ac" - grapheme_strstr before flag is FALSE = aba%CC%8Ac == aba%CC%8Ac
1066
1067function grapheme_stristr($haystack, $needle, $before_needle = FALSE) {}
1068
1069find "O%CC%88" in "aa%CC%8Abco%CC%88" - grapheme_stristr = o%CC%88 == o%CC%88
1070find "o" in "aa%CC%8Abco%CC%88O" - grapheme_stristr = O == O
1071find "o" in "aa%CC%8Abco%CC%88" - grapheme_stristr = false == false
1072find "a%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_stristr = a%CC%8Abc == a%CC%8Abc
1073find "A%CC%8A" in "aa%CC%8Abc" - grapheme_stristr = a%CC%8Abc == a%CC%8Abc
1074find "a%CC%8A" in "abc" - grapheme_stristr = false == false
1075find "A" in "a%CC%8Abc" - grapheme_stristr = false == false
1076find "d" in "abc" - grapheme_stristr = false == false
1077find "C" in "abc" - grapheme_stristr = c == c
1078find "b" in "aBc" - grapheme_stristr = Bc == Bc
1079find "A" in "abc" - grapheme_stristr = abc == abc
1080find "ab" in "abC" - grapheme_stristr = abC == abC
1081find "aBc" in "abc" - grapheme_stristr = abc == abc
1082find "bc" in "abC" - grapheme_stristr = bC == bC
1083find "A" in "abc" - grapheme_stristr before flag is FALSE = abc == abc
1084find "a" in "abc" - grapheme_stristr before flag is TRUE =  ==
1085find "b" in "aBc" - grapheme_stristr before flag is TRUE = a == a
1086find "C" in "abc" - grapheme_stristr before flag is TRUE = ab == ab
1087find "bab" in "aBabc" - grapheme_stristr before flag is TRUE = a == a
1088find "aBc" in "ababc" - grapheme_stristr before flag is TRUE = ab == ab
1089find "abC" in "ababc" - grapheme_stristr before flag is FALSE = abc == abc
1090find "d" in "aba%CC%8Ac" - grapheme_stristr = false == false
1091find "a" in "bca%CC%8AA" - grapheme_stristr = A == A
1092find "B" in "aa%CC%8Abc" - grapheme_stristr = bc == bc
1093find "a" in "A%CC%8Abc" - grapheme_stristr = false == false
1094find "Ab" in "a%CC%8Aabc" - grapheme_stristr = abc == abc
1095find "abc" in "abcA%CC%8A" - grapheme_stristr = abcA%CC%8A == abcA%CC%8A
1096find "A%CC%8Abc" in "aa%CC%8Abc" - grapheme_stristr = a%CC%8Abc == a%CC%8Abc
1097find "a%CC%8A" in "aA%CC%8Abc" - grapheme_stristr before flag is FALSE = A%CC%8Abc == A%CC%8Abc
1098find "A" in "aa%CC%8Abc" - grapheme_stristr before flag is TRUE =  ==
1099find "b" in "a%CC%8AaBc" - grapheme_stristr before flag is TRUE = a%CC%8Aa == a%CC%8Aa
1100find "C" in "aba%CC%8Ac" - grapheme_stristr before flag is TRUE = aba%CC%8A == aba%CC%8A
1101find "baa%CC%8Ab" in "abaA%CC%8Abc" - grapheme_stristr before flag is TRUE = a == a
1102find "aBcA%CC%8A" in "ababca%CC%8A" - grapheme_stristr before flag is TRUE = ab == ab
1103find "aba%CC%8Ac" in "abABA%CC%8Ac" - grapheme_stristr before flag is FALSE = ABA%CC%8Ac == ABA%CC%8Ac
1104
1105function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_COUNT, $start = 0[, $next])
1106
1107extract from "abc" "3" graphemes - grapheme_extract = abc == abc
1108extract from "abc" "2" graphemes - grapheme_extract = ab == ab
1109extract from "abc" "1" graphemes - grapheme_extract = a == a
1110extract from "abc" "0" graphemes - grapheme_extract =  ==
1111extract from "abc" "1" graphemes - grapheme_extract starting at byte position 0 = a == a
1112extract from "abc" "1" graphemes - grapheme_extract starting at byte position 1 = b == b
1113extract from "abc" "1" graphemes - grapheme_extract starting at byte position 2 = c == c
1114extract from "abc" "0" graphemes - grapheme_extract starting at byte position 2 =  ==
1115extract from "abc" "3" graphemes - grapheme_extract starting at byte position 0 with $next = abc == abc $next=3 == 3
1116extract from "abc" "2" graphemes - grapheme_extract starting at byte position 0 with $next = ab == ab $next=2 == 2
1117extract from "abc" "1" graphemes - grapheme_extract starting at byte position 0 with $next = a == a $next=1 == 1
1118extract from "abc" "0" graphemes - grapheme_extract starting at byte position 0 with $next =  ==  $next=0 == 0
1119extract from "abc" "1" graphemes - grapheme_extract starting at byte position 0 with $next = a == a $next=1 == 1
1120extract from "abc" "1" graphemes - grapheme_extract starting at byte position 1 with $next = b == b $next=2 == 2
1121extract from "abc" "1" graphemes - grapheme_extract starting at byte position 2 with $next = c == c $next=3 == 3
1122extract from "abc" "1" graphemes - grapheme_extract starting at byte position -2 with $next = b == b $next=2 == 2
1123extract from "abc" "0" graphemes - grapheme_extract starting at byte position 2 with $next =  ==  $next=2 == 2
1124extract from "http%3A%2F%2Fnews.bbc.co.uk%2F2%2Fhi%2Fmiddle_east%2F7831588.stm" "48" graphemes - grapheme_extract starting at byte position 48 with $next = tm == tm $next=50 == 50
1125extract from "a%CC%8Abc" "3" graphemes - grapheme_extract = a%CC%8Abc == a%CC%8Abc
1126extract from "a%CC%8Abc" "2" graphemes - grapheme_extract = a%CC%8Ab == a%CC%8Ab
1127extract from "a%CC%8Abc" "1" graphemes - grapheme_extract = a%CC%8A == a%CC%8A
1128extract from "a%CC%8Abc" "3" graphemes - grapheme_extract starting at byte position 0 with $next = a%CC%8Abc == a%CC%8Abc $next=5 == 5
1129extract from "a%CC%8Abc" "2" graphemes - grapheme_extract starting at byte position 0 with $next = a%CC%8Ab == a%CC%8Ab $next=4 == 4
1130extract from "a%CC%8Abc" "1" graphemes - grapheme_extract starting at byte position 0 with $next = a%CC%8A == a%CC%8A $next=3 == 3
1131extract from "a%CC%8Abcde" "2" graphemes - grapheme_extract starting at byte position 3 with $next = bc == bc $next=5 == 5
1132extract from "a%CC%8Abcde" "2" graphemes - grapheme_extract starting at byte position -4 with $next = bc == bc $next=5 == 5
1133extract from "a%CC%8Abcde" "2" graphemes - grapheme_extract starting at byte position 4 with $next = cd == cd $next=6 == 6
1134extract from "a%CC%8Abcde" "2" graphemes - grapheme_extract starting at byte position -7 with $next = a%CC%8Ab == a%CC%8Ab $next=4 == 4
1135extract from "a%CC%8Abcdea%CC%8Af" "4" graphemes - grapheme_extract starting at byte position 5 with $next = dea%CC%8Af == dea%CC%8Af $next=11 == 11
1136extract from "a%CC%8Abcdea%CC%8Af" "4" graphemes - grapheme_extract starting at byte position -6 with $next = dea%CC%8Af == dea%CC%8Af $next=11 == 11
1137extract from "a%CC%8Ao%CC%88o%CC%88" "3" graphemes - grapheme_extract = a%CC%8Ao%CC%88o%CC%88 == a%CC%8Ao%CC%88o%CC%88
1138extract from "a%CC%8Ao%CC%88o%CC%88" "2" graphemes - grapheme_extract = a%CC%8Ao%CC%88 == a%CC%8Ao%CC%88
1139extract from "a%CC%8Ao%CC%88c" "1" graphemes - grapheme_extract = a%CC%8A == a%CC%8A
1140extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "1" graphemes - grapheme_extract starting at byte position 0 = o%CC%88 == o%CC%88
1141extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "1" graphemes - grapheme_extract starting at byte position 2 = o%CC%88 == o%CC%88
1142extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "1" graphemes - grapheme_extract starting at byte position 3 = o%CC%88 == o%CC%88
1143extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "1" graphemes - grapheme_extract starting at byte position 4 = %CC%88 == %CC%88
1144extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract starting at byte position 0 = o%CC%88o%CC%88 == o%CC%88o%CC%88
1145extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract starting at byte position 2 = o%CC%88o%CC%88 == o%CC%88o%CC%88
1146extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract starting at byte position 3 = o%CC%88o%CC%88 == o%CC%88o%CC%88
1147extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract starting at byte position 4 = %CC%88o%CC%88 == %CC%88o%CC%88
1148extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract starting at byte position 7 = %CC%88o%CC%88 == %CC%88o%CC%88
1149extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract starting at byte position 8 = o%CC%88 == o%CC%88
1150extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract starting at byte position 10 = %CC%88 == %CC%88
1151extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract starting at byte position 11 = false == false
1152
1153function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_MAXBYTES, $start = 0)
1154
1155extract from "abc" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = abc == abc
1156extract from "abc" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = ab == ab
1157extract from "abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a == a
1158extract from "abc" "0" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES =  ==
1159extract from "a%CC%8Abc" "5" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8Abc == a%CC%8Abc
1160extract from "a%CC%8Abc" "4" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8Ab == a%CC%8Ab
1161extract from "a%CC%8Abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES =  ==
1162extract from "a%CC%8Ao%CC%88o%CC%88" "9" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8Ao%CC%88o%CC%88 == a%CC%8Ao%CC%88o%CC%88
1163extract from "a%CC%8Ao%CC%88o%CC%88" "10" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8Ao%CC%88o%CC%88 == a%CC%8Ao%CC%88o%CC%88
1164extract from "a%CC%8Ao%CC%88o%CC%88" "11" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8Ao%CC%88o%CC%88 == a%CC%8Ao%CC%88o%CC%88
1165extract from "a%CC%8Ao%CC%88o%CC%88" "6" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8Ao%CC%88 == a%CC%8Ao%CC%88
1166extract from "a%CC%8Ao%CC%88c" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8A == a%CC%8A
1167extract from "a%CC%8Ao%CC%88c" "4" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8A == a%CC%8A
1168extract from "a%CC%8Ao%CC%88c" "5" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8A == a%CC%8A
1169extract from "a%CC%8Ao%CC%88c" "6" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8Ao%CC%88 == a%CC%8Ao%CC%88
1170extract from "a%CC%8Ao%CC%88c" "7" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8Ao%CC%88c == a%CC%8Ao%CC%88c
1171extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 0 = o%CC%88 == o%CC%88
1172extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 2 = o%CC%88 == o%CC%88
1173extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 3 = o%CC%88 == o%CC%88
1174extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 4 = %CC%88 == %CC%88
1175extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "6" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 0 = o%CC%88o%CC%88 == o%CC%88o%CC%88
1176extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "6" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 2 = o%CC%88o%CC%88 == o%CC%88o%CC%88
1177extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "6" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 3 = o%CC%88o%CC%88 == o%CC%88o%CC%88
1178extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "5" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 4 = %CC%88o%CC%88 == %CC%88o%CC%88
1179extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "5" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 7 = %CC%88o%CC%88 == %CC%88o%CC%88
1180extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 8 = o%CC%88 == o%CC%88
1181extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 10 = %CC%88 == %CC%88
1182extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 11 = false == false
1183
1184function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_MAXCHARS, $start = 0)
1185
1186extract from "abc" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = abc == abc
1187extract from "abc" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = ab == ab
1188extract from "abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = a == a
1189extract from "abc" "0" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS =  ==
1190extract from "abco%CC%88" "0" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS =  ==
1191extract from "abco%CC%88" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = a == a
1192extract from "abco%CC%88" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = ab == ab
1193extract from "abco%CC%88" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = abc == abc
1194extract from "abco%CC%88" "4" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = abc == abc
1195extract from "abco%CC%88" "5" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = abco%CC%88 == abco%CC%88
1196extract from "abco%CC%88" "6" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = abco%CC%88 == abco%CC%88
1197extract from "o%CC%88abc" "0" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS =  ==
1198extract from "o%CC%88abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS =  ==
1199extract from "o%CC%88abc" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88 == o%CC%88
1200extract from "o%CC%88abc" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88a == o%CC%88a
1201extract from "o%CC%88abc" "4" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88ab == o%CC%88ab
1202extract from "o%CC%88abca%CC%8Axyz" "5" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88abc == o%CC%88abc
1203extract from "o%CC%88abca%CC%8Axyz" "6" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88abc == o%CC%88abc
1204extract from "o%CC%88abca%CC%8Axyz" "7" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88abca%CC%8A == o%CC%88abca%CC%8A
1205extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88abca%CC%8Ax == o%CC%88abca%CC%8Ax
1206extract from "abc" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 0 = abc == abc
1207extract from "abc" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 1 = bc == bc
1208extract from "abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 2 = c == c
1209extract from "abc" "0" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 3 = false == false
1210extract from "abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 3 = false == false
1211extract from "abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 999 = false == false
1212extract from "o%CC%88abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 6 = false == false
1213extract from "o%CC%88abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 999 = false == false
1214extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 0 = o%CC%88abca%CC%8Ax == o%CC%88abca%CC%8Ax
1215extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 1 = %CC%88abca%CC%8Axy == %CC%88abca%CC%8Axy
1216extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 2 = abca%CC%8Axyz == abca%CC%8Axyz
1217extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 3 = abca%CC%8Axyz == abca%CC%8Axyz
1218extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 4 = bca%CC%8Axyz == bca%CC%8Axyz
1219extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 5 = ca%CC%8Axyz == ca%CC%8Axyz
1220extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 6 = a%CC%8Axyz == a%CC%8Axyz
1221