xref: /PHP-8.4/ext/intl/tests/grapheme.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        $arg0 = urlencode($test[0]);
402        $res_str .= "substring of \"$arg0\" from \"$test[1]\" - grapheme_substr";
403        if ( 3 == count( $test ) ) {
404            try {
405                $result = grapheme_substr($test[0], $test[1]);
406            } catch (ValueError $exception) {
407                $res_str .= ": " . $exception->getMessage() . "\n";
408            }
409        }
410        else {
411            $res_str .= " with length $test[2]";
412            try {
413                $result = grapheme_substr($test[0], $test[1], $test[2]);
414            } catch (ValueError $exception) {
415                $res_str .= ": " . $exception->getMessage() . "\n";
416            }
417        }
418        $res_str .= " = ";
419        if ( $result === false ) {
420            $res_str .= 'false';
421        }
422        else {
423            $res_str .= urlencode($result);
424        }
425        $res_str .= " == " . urlencode($test[count($test)-1]) . check_result($result, $test[count($test)-1]) . "\n";
426    }
427
428
429    //=====================================================================================
430    $res_str .= "\n" . 'function grapheme_strstr($haystack, $needle, $before_needle = FALSE) {}' . "\n\n";
431
432    $tests = array(
433        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "o", "o", "o" ),
434        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "o", "false" ),
435        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, $char_o_diaeresis_nfd, $char_o_diaeresis_nfd ),
436        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, $char_a_ring_nfd . "bc"),
437        array( "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, $char_a_ring_nfd . "bc"),
438        array( "abc", $char_a_ring_nfd, "false" ),
439        array( $char_a_ring_nfd . "bc", "a", "false" ),
440        array( "abc", "d", "false" ),
441        array( "abc", "c", "c" ),
442        array( "abc", "b", "bc" ),
443        array( "abc", "a", "abc" ),
444        array( "abc", "ab", "abc" ),
445        array( "abc", "abc", "abc" ),
446        array( "abc", "bc", "bc" ),
447        array( "abc", "a", FALSE, "abc" ),
448        array( "abc", "a", TRUE, "" ),
449        array( "abc", "b", TRUE, "a" ),
450        array( "abc", "c", TRUE, "ab" ),
451        array( "ababc", "bab", TRUE, "a" ),
452        array( "ababc", "abc", TRUE, "ab" ),
453        array( "ababc", "abc", FALSE, "abc" ),
454
455        array( "ab" . $char_a_ring_nfd . "c", "d", "false" ),
456        array( "bc" . $char_a_ring_nfd . "a", "a", "a" ),
457        array( "a" . $char_a_ring_nfd . "bc", "b", "bc" ),
458        array( $char_a_ring_nfd . "bc", "a", "false" ),
459        array( $char_a_ring_nfd . "abc", "ab", "abc" ),
460        array( "abc" . $char_a_ring_nfd, "abc", "abc" . $char_a_ring_nfd),
461        array( "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd . "bc", $char_a_ring_nfd . "bc" ),
462        array( "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, FALSE, $char_a_ring_nfd . "bc"),
463        array( "a" . $char_a_ring_nfd . "bc", "a", TRUE, "" ),
464        array( $char_a_ring_nfd . "abc", "b", TRUE, $char_a_ring_nfd . "a" ),
465        array( "ab" . $char_a_ring_nfd . "c", "c", TRUE, "ab" . $char_a_ring_nfd ),
466        array( "aba" . $char_a_ring_nfd . "bc", "ba" . $char_a_ring_nfd . "b", TRUE, "a" ),
467        array( "ababc" . $char_a_ring_nfd, "abc" . $char_a_ring_nfd, TRUE, "ab" ),
468        array( "abab" . $char_a_ring_nfd . "c", "ab" . $char_a_ring_nfd . "c", FALSE, "ab" . $char_a_ring_nfd . "c" ),
469
470    );
471
472    foreach( $tests as $test ) {
473        $arg1 = urlencode($test[1]);
474        $arg0 = urlencode($test[0]);
475        $res_str .= "find \"$arg1\" in \"$arg0\" - grapheme_strstr";
476        if ( 3 == count( $test ) ) {
477            try {
478                $result = grapheme_strstr($test[0], $test[1]);
479            } catch (ValueError $exception) {
480                $res_str .= ": " . $exception->getMessage() . "\n";
481            }
482        }
483        else {
484            $res_str .= " before flag is " . ( $test[2] ? "TRUE" : "FALSE" );
485            try {
486                $result = grapheme_strstr($test[0], $test[1], $test[2]);
487            } catch (ValueError $exception) {
488                $res_str .= ": " . $exception->getMessage() . "\n";
489            }
490        }
491        $res_str .= " = ";
492        if ( $result === false ) {
493            $res_str .= 'false';
494        }
495        else {
496            $res_str .= urlencode($result);
497        }
498        $res_str .= " == " . urlencode($test[count($test)-1]) . check_result($result, $test[count($test)-1]) . "\n";
499    }
500
501
502    //=====================================================================================
503    $res_str .= "\n" . 'function grapheme_stristr($haystack, $needle, $before_needle = FALSE) {}' . "\n\n";
504
505    $tests = array(
506        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, $char_O_diaeresis_nfd, $char_o_diaeresis_nfd ),
507        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd . "O", "o", "O" ),
508        array( "a" . $char_a_ring_nfd . "bc" . $char_o_diaeresis_nfd, "o", "false" ),
509        array( $char_o_diaeresis_nfd . "a" . $char_a_ring_nfd . "bc", $char_a_ring_nfd, $char_a_ring_nfd . "bc"),
510        array( "a" . $char_a_ring_nfd . "bc", $char_A_ring_nfd, $char_a_ring_nfd . "bc"),
511        array( "abc", $char_a_ring_nfd, "false" ),
512        array( $char_a_ring_nfd . "bc", "A", "false" ),
513        array( "abc", "d", "false" ),
514        array( "abc", "C", "c" ),
515        array( "aBc", "b", "Bc" ),
516        array( "abc", "A", "abc" ),
517        array( "abC", "ab", "abC" ),
518        array( "abc", "aBc", "abc" ),
519        array( "abC", "bc", "bC" ),
520        array( "abc", "A", FALSE, "abc" ),
521        array( "abc", "a", TRUE, "" ),
522        array( "aBc", "b", TRUE, "a" ),
523        array( "abc", "C", TRUE, "ab" ),
524        array( "aBabc", "bab", TRUE, "a" ),
525        array( "ababc", "aBc", TRUE, "ab" ),
526        array( "ababc", "abC", FALSE, "abc" ),
527
528        array( "ab" . $char_a_ring_nfd . "c", "d", "false" ),
529        array( "bc" . $char_a_ring_nfd . "A", "a", "A" ),
530        array( "a" . $char_a_ring_nfd . "bc", "B", "bc" ),
531        array( $char_A_ring_nfd . "bc", "a", "false" ),
532        array( $char_a_ring_nfd . "abc", "Ab", "abc" ),
533        array( "abc" . $char_A_ring_nfd, "abc", "abc" . $char_A_ring_nfd),
534        array( "a" . $char_a_ring_nfd . "bc", $char_A_ring_nfd . "bc", $char_a_ring_nfd . "bc" ),
535        array( "a" . $char_A_ring_nfd . "bc", $char_a_ring_nfd, FALSE, $char_A_ring_nfd . "bc" ),
536        array( "a" . $char_a_ring_nfd . "bc", "A", TRUE, "" ),
537        array( $char_a_ring_nfd . "aBc", "b", TRUE, $char_a_ring_nfd . "a" ),
538        array( "ab" . $char_a_ring_nfd . "c", "C", TRUE, "ab" . $char_a_ring_nfd ),
539        array( "aba" . $char_A_ring_nfd . "bc", "ba" . $char_a_ring_nfd . "b", TRUE, "a" ),
540        array( "ababc" . $char_a_ring_nfd, "aBc" . $char_A_ring_nfd, TRUE, "ab" ),
541        array( "abAB" . $char_A_ring_nfd . "c", "ab" . $char_a_ring_nfd . "c", FALSE, "AB" . $char_A_ring_nfd . "c" ),
542
543    );
544
545    foreach( $tests as $test ) {
546        $arg1 = urlencode($test[1]);
547        $arg0 = urlencode($test[0]);
548        $res_str .= "find \"$arg1\" in \"$arg0\" - grapheme_stristr";
549        if ( 3 == count( $test ) ) {
550            $result = grapheme_stristr($test[0], $test[1]);
551        }
552        else {
553            $res_str .= " before flag is " . ( $test[2] ? "TRUE" : "FALSE" );
554            $result = grapheme_stristr($test[0], $test[1], $test[2]);
555        }
556        $res_str .= " = ";
557        if ( $result === false ) {
558            $res_str .= 'false';
559        }
560        else {
561            $res_str .= urlencode($result);
562        }
563        $res_str .= " == " . urlencode($test[count($test)-1]) . check_result($result, $test[count($test)-1]) . "\n";
564    }
565
566
567    //=====================================================================================
568    $res_str .= "\n" . 'function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_COUNT, $start = 0[, $next])' . "\n\n";
569
570    $tests = array(
571        // haystack, count, [[offset], [next]], result
572        array( "abc", 3, "abc" ),
573        array( "abc", 2, "ab" ),
574        array( "abc", 1, "a" ),
575        array( "abc", 0, "" ),
576        array( "abc", 1, 0, "a" ),
577        array( "abc", 1, 1, "b" ),
578        array( "abc", 1, 2, "c" ),
579        array( "abc", 0, 2, "" ),
580
581        array( "abc", 3, 0, 3, "abc" ),
582        array( "abc", 2, 0, 2, "ab" ),
583        array( "abc", 1, 0, 1, "a" ),
584        array( "abc", 0, 0, 0, "" ),
585        array( "abc", 1, 0, 1, "a" ),
586        array( "abc", 1, 1, 2, "b" ),
587        array( "abc", 1, 2, 3, "c" ),
588        array( "abc", 1, -2, 2, "b" ),
589        array( "abc", 0, 2, 2, "" ),
590        array( "http://news.bbc.co.uk/2/hi/middle_east/7831588.stm", 48, 48 , 50 , "tm" ),
591
592        array( $char_a_ring_nfd . "bc", 3, $char_a_ring_nfd . "bc" ),
593        array( $char_a_ring_nfd . "bc", 2, $char_a_ring_nfd . "b" ),
594        array( $char_a_ring_nfd . "bc", 1, $char_a_ring_nfd . "" ),
595        array( $char_a_ring_nfd . "bc", 3, 0, 5, $char_a_ring_nfd . "bc" ),
596        array( $char_a_ring_nfd . "bc", 2, 0, 4, $char_a_ring_nfd . "b" ),
597        array( $char_a_ring_nfd . "bc", 1, 0, 3, $char_a_ring_nfd . "" ),
598        array( $char_a_ring_nfd . "bcde", 2, 3, 5, "bc" ),
599        array( $char_a_ring_nfd . "bcde", 2, -4, 5, "bc" ),
600        array( $char_a_ring_nfd . "bcde", 2, 4, 6, "cd" ),
601        array( $char_a_ring_nfd . "bcde", 2, -7, 4, $char_a_ring_nfd . "b" ),
602        array( $char_a_ring_nfd . "bcde" . $char_a_ring_nfd . "f", 4, 5, 11, "de" . $char_a_ring_nfd . "f" ),
603        array( $char_a_ring_nfd . "bcde" . $char_a_ring_nfd . "f", 4, -6, 11, "de" . $char_a_ring_nfd . "f" ),
604
605        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 ),
606        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, $char_a_ring_nfd . $char_o_diaeresis_nfd ),
607        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . "c", 1, $char_a_ring_nfd . "" ),
608
609        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 1, 0, $char_o_diaeresis_nfd),
610        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 1, 2, $char_o_diaeresis_nfd),
611        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 1, 3, $char_o_diaeresis_nfd),
612        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 1, 4, $char_diaeresis),
613
614        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),
615        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),
616        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),
617        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),
618        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),
619        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 8, $char_o_diaeresis_nfd),
620        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 10, $char_diaeresis),
621        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 11, "false"),
622
623    );
624
625    $next = -1;
626    foreach( $tests as $test ) {
627        $arg0 = urlencode($test[0]);
628        $res_str .= "extract from \"$arg0\" \"$test[1]\" graphemes - grapheme_extract";
629        if ( 3 == count( $test ) ) {
630            $result = grapheme_extract($test[0], $test[1]);
631        }
632        elseif ( 4 == count ( $test ) ) {
633            $res_str .= " starting at byte position $test[2]";
634            $result = grapheme_extract($test[0], $test[1], GRAPHEME_EXTR_COUNT, $test[2]);
635        }
636        else {
637            $res_str .= " starting at byte position $test[2] with \$next";
638            $result = grapheme_extract($test[0], $test[1], GRAPHEME_EXTR_COUNT, $test[2], $next);
639        }
640        $res_str .= " = ";
641        if ( $result === false ) {
642            $res_str .= 'false';
643        }
644        else {
645            $res_str .= urlencode($result);
646        }
647        $res_str .= " == " . urlencode($test[count($test)-1]) . check_result($result, $test[count($test)-1]);
648        if ( 5 == count ( $test ) ) {
649            $res_str .= " \$next=$next == $test[3] ";
650            if ( $next != $test[3] ) {
651                $res_str .= "***FAILED***";
652            }
653        }
654        $res_str .= "\n";
655    }
656
657
658    //=====================================================================================
659    $res_str .= "\n" . 'function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_MAXBYTES, $start = 0)' . "\n\n";
660
661    $tests = array(
662        array( "abc", 3, "abc" ),
663        array( "abc", 2, "ab" ),
664        array( "abc", 1, "a" ),
665        array( "abc", 0, "" ),
666        array( $char_a_ring_nfd . "bc", 5, $char_a_ring_nfd . "bc" ),
667        array( $char_a_ring_nfd . "bc", 4, $char_a_ring_nfd . "b" ),
668        array( $char_a_ring_nfd . "bc", 1, "" ),
669        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 ),
670        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 ),
671        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 ),
672        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 6, $char_a_ring_nfd . $char_o_diaeresis_nfd ),
673        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . "c", 3, $char_a_ring_nfd . "" ),
674        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . "c", 4, $char_a_ring_nfd . "" ),
675        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . "c", 5, $char_a_ring_nfd . "" ),
676        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . "c", 6, $char_a_ring_nfd . $char_o_diaeresis_nfd  ),
677        array( $char_a_ring_nfd . $char_o_diaeresis_nfd . "c", 7, $char_a_ring_nfd . $char_o_diaeresis_nfd . "c" ),
678
679        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 3, 0, $char_o_diaeresis_nfd),
680        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 3, 2, $char_o_diaeresis_nfd),
681        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 3, 3, $char_o_diaeresis_nfd),
682        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 3, 4, $char_diaeresis),
683
684        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),
685        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),
686        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),
687        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),
688        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),
689        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 3, 8, $char_o_diaeresis_nfd),
690        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 10, $char_diaeresis),
691        array( $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd . $char_o_diaeresis_nfd, 2, 11, "false"),
692
693    );
694
695    foreach( $tests as $test ) {
696        $arg0 = urlencode($test[0]);
697        $res_str .= "extract from \"$arg0\" \"$test[1]\" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES";
698        if ( 3 == count( $test ) ) {
699            $result = grapheme_extract($test[0], $test[1], GRAPHEME_EXTR_MAXBYTES);
700        }
701        else {
702            $res_str .= " starting at byte position $test[2]";
703            $result = grapheme_extract($test[0], $test[1], GRAPHEME_EXTR_MAXBYTES, $test[2]);
704        }
705        $res_str .= " = ";
706        if ( $result === false ) {
707            $res_str .= 'false';
708        }
709        else {
710            $res_str .= urlencode($result);
711        }
712        $res_str .= " == " . urlencode($test[count($test)-1]) . check_result($result, $test[count($test)-1]) . "\n";
713    }
714
715
716    //=====================================================================================
717    $res_str .= "\n" . 'function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_MAXCHARS, $start = 0)' . "\n\n";
718
719    $tests = array(
720        array( "abc", 3, "abc" ),
721        array( "abc", 2, "ab" ),
722        array( "abc", 1, "a" ),
723        array( "abc", 0, "" ),
724        array( "abc" . $char_o_diaeresis_nfd, 0, "" ),
725        array( "abc" . $char_o_diaeresis_nfd, 1, "a" ),
726        array( "abc" . $char_o_diaeresis_nfd, 2, "ab" ),
727        array( "abc" . $char_o_diaeresis_nfd, 3, "abc" ),
728        array( "abc" . $char_o_diaeresis_nfd, 4, "abc" ),
729        array( "abc" . $char_o_diaeresis_nfd, 5, "abc" . $char_o_diaeresis_nfd),
730        array( "abc" . $char_o_diaeresis_nfd, 6, "abc" . $char_o_diaeresis_nfd),
731        array( $char_o_diaeresis_nfd . "abc", 0, "" ),
732        array( $char_o_diaeresis_nfd . "abc", 1, "" ),
733        array( $char_o_diaeresis_nfd . "abc", 2, $char_o_diaeresis_nfd ),
734        array( $char_o_diaeresis_nfd . "abc", 3, $char_o_diaeresis_nfd . "a" ),
735        array( $char_o_diaeresis_nfd . "abc", 4, $char_o_diaeresis_nfd . "ab" ),
736        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 5, $char_o_diaeresis_nfd . "abc" ),
737        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 6, $char_o_diaeresis_nfd . "abc" ),
738        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 7, $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd ),
739        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "x" ),
740
741        array( "abc", 3, 0, "abc" ),
742        array( "abc", 2, 1, "bc" ),
743        array( "abc", 1, 2, "c" ),
744        array( "abc", 0, 3, "false" ),
745        array( "abc", 1, 3, "false" ),
746        array( "abc", 1, 999, "false" ),
747        array( $char_o_diaeresis_nfd . "abc", 1, 6, "false" ),
748        array( $char_o_diaeresis_nfd . "abc", 1, 999, "false" ),
749        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 0, $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "x" ),
750        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 1, $char_diaeresis . "abc" . $char_a_ring_nfd . "xy" ),
751        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 2, "abc" . $char_a_ring_nfd . "xyz" ),
752        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 3, "abc" . $char_a_ring_nfd . "xyz" ),
753        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 4, "bc" . $char_a_ring_nfd . "xyz" ),
754        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 5, "c" . $char_a_ring_nfd . "xyz" ),
755        array( $char_o_diaeresis_nfd . "abc" . $char_a_ring_nfd . "xyz", 8, 6, $char_a_ring_nfd . "xyz" ),
756
757    );
758
759    foreach( $tests as $test ) {
760        $arg0 = urlencode($test[0]);
761        $res_str .= "extract from \"$arg0\" \"$test[1]\" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS";
762        if ( 3 == count( $test ) ) {
763            $result = grapheme_extract($test[0], $test[1], GRAPHEME_EXTR_MAXCHARS);
764        }
765        else {
766            $res_str .= " starting at byte position $test[2]";
767            $result = grapheme_extract($test[0], $test[1], GRAPHEME_EXTR_MAXCHARS, $test[2]);
768        }
769        $res_str .= " = ";
770        if ( $result === false ) {
771            $res_str .= 'false';
772        }
773        else {
774            $res_str .= urlencode($result);
775        }
776        $res_str .= " == " . urlencode($test[count($test)-1]) . check_result($result, $test[count($test)-1]) . "\n";
777    }
778
779
780    //=====================================================================================
781
782    return $res_str;
783}
784
785echo ut_main();
786
787function check_result($result, $expected) {
788
789    if ( $result === false ) {
790            $result = 'false';
791    }
792
793    if ( strcmp($result, $expected) != 0 ) {
794        return " **FAILED** ";
795    }
796
797    return "";
798}
799
800?>
801--EXPECT--
802function grapheme_strlen($string) {}
803
804"hindi" in devanagari strlen 3
805"ab" + "hindi" + "cde" strlen 8
806"" strlen 0
807char_a_ring_nfd strlen 1
808char_a_ring_nfd + "bc" strlen 3
809"abc" strlen 3
810
811function grapheme_strpos($haystack, $needle, $offset = 0) {}
812
813find "o" in "aa%CC%8Abco%CC%88o" - grapheme_strpos = 5 == 5
814find "o" in "aa%CC%8Abco%CC%88" - grapheme_strpos = false == false
815find "o%CC%88" in "aa%CC%8Abco%CC%88" - grapheme_strpos = 4 == 4
816find "a%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_strpos = 2 == 2
817find "a%CC%8A" in "aa%CC%8Abc" - grapheme_strpos = 1 == 1
818find "a%CC%8A" in "abc" - grapheme_strpos = false == false
819find "a" in "a%CC%8Abc" - grapheme_strpos = false == false
820find "d" in "abc" - grapheme_strpos = false == false
821find "c" in "abc" - grapheme_strpos = 2 == 2
822find "b" in "abc" - grapheme_strpos = 1 == 1
823find "a" in "abc" - grapheme_strpos = 0 == 0
824find "a" in "abc" - grapheme_strpos from 0 = 0 == 0
825find "a" in "abc" - grapheme_strpos from 1 = false == false
826find "a" in "abc" - grapheme_strpos from -1 = false == false
827find "a" in "ababc" - grapheme_strpos from 1 = 2 == 2
828find "o" in "aoa%CC%8Abco%CC%88o" - grapheme_strpos from 2 = 6 == 6
829find "o" in "aoa%CC%8Abco%CC%88o" - grapheme_strpos from -1 = 6 == 6
830find "o" in "aoa%CC%8Abco%CC%88o" - grapheme_strpos from -5 = 6 == 6
831find "a%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abc" - grapheme_strpos from 2 = 3 == 3
832find "a%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abc" - grapheme_strpos from -4 = 3 == 3
833find "op" in "aa%CC%8Abco%CC%88opq" - grapheme_strpos = 5 == 5
834find "opq" in "aa%CC%8Abco%CC%88opq" - grapheme_strpos = 5 == 5
835find "abc" in "aa%CC%8Abco%CC%88" - grapheme_strpos = false == false
836find "o%CC%88bco%CC%88" in "aa%CC%8Abco%CC%88bco%CC%88" - grapheme_strpos = 4 == 4
837find "a%CC%8Abc" in "o%CC%88aa%CC%8Abc" - grapheme_strpos = 2 == 2
838find "a%CC%8Abc" in "aa%CC%8Abc" - grapheme_strpos = 1 == 1
839find "a%CC%8Abc" in "abc" - grapheme_strpos = false == false
840find "abcdefg" in "a%CC%8Abc" - grapheme_strpos = false == false
841find "defghijklmnopq" in "abc" - grapheme_strpos = false == false
842find "ab" in "abc" - grapheme_strpos = 0 == 0
843find "bc" in "abc" - grapheme_strpos = 1 == 1
844find "abc" in "abc" - grapheme_strpos = 0 == 0
845find "abcd" in "abc" - grapheme_strpos = false == false
846find "ab" in "abc" - grapheme_strpos from 0 = 0 == 0
847find "abc" in "abc" - grapheme_strpos from 0 = 0 == 0
848find "abc" in "abc" - grapheme_strpos from 1 = false == false
849find "ab" in "ababc" - grapheme_strpos from 1 = 2 == 2
850find "abc" in "ababc" - grapheme_strpos from 1 = 2 == 2
851find "oa%CC%8Abc" in "aoa%CC%8Abco%CC%88oa%CC%8Abc" - grapheme_strpos from 2 = 6 == 6
852find "oa%CC%8Abc" in "aoa%CC%8Abco%CC%88oa%CC%8Abc" - grapheme_strpos from -8 = 6 == 6
853find "a%CC%8Abca%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abca%CC%8Adef" - grapheme_strpos from 2 = 3 == 3
854
855function grapheme_stripos($haystack, $needle, $offset = 0) {}
856
857find "o" in "aoa%CC%8Abco%CC%88O" - grapheme_stripos from 2 = 6 == 6
858find "o" in "aoa%CC%8Abco%CC%88Oo" - grapheme_stripos from -6 = 6 == 6
859find "a%CC%8A" in "o%CC%88a%CC%8AaA%CC%8Abc" - grapheme_stripos from 2 = 3 == 3
860find "o" in "aa%CC%8Abco%CC%88O" - grapheme_stripos = 5 == 5
861find "O" in "aa%CC%8Abco%CC%88" - grapheme_stripos = false == false
862find "o%CC%88" in "aa%CC%8AbcO%CC%88" - grapheme_stripos = 4 == 4
863find "o%CC%88" in "aa%CC%8AbcO%CC%88" - grapheme_stripos from -1 = 4 == 4
864find "A%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_stripos = 2 == 2
865find "a%CC%8A" in "aA%CC%8Abc" - grapheme_stripos = 1 == 1
866find "a%CC%8A" in "Abc" - grapheme_stripos = false == false
867find "A" in "a%CC%8Abc" - grapheme_stripos = false == false
868find "D" in "abc" - grapheme_stripos = false == false
869find "c" in "abC" - grapheme_stripos = 2 == 2
870find "B" in "abc" - grapheme_stripos = 1 == 1
871find "a" in "Abc" - grapheme_stripos = 0 == 0
872find "A" in "abc" - grapheme_stripos from 0 = 0 == 0
873find "a" in "Abc" - grapheme_stripos from 1 = false == false
874find "A" in "ababc" - grapheme_stripos from 1 = 2 == 2
875find "oP" in "aa%CC%8Abco%CC%88Opq" - grapheme_stripos = 5 == 5
876find "opQ" in "aa%CC%8Abco%CC%88Opq" - grapheme_stripos = 5 == 5
877find "abc" in "aa%CC%8Abco%CC%88" - grapheme_stripos = false == false
878find "O%CC%88bco%CC%88" in "aa%CC%8Abco%CC%88bCo%CC%88" - grapheme_stripos = 4 == 4
879find "A%CC%8Abc" in "o%CC%88aa%CC%8ABc" - grapheme_stripos = 2 == 2
880find "a%CC%8Abc" in "aa%CC%8ABC" - grapheme_stripos = 1 == 1
881find "a%CC%8ABC" in "abc" - grapheme_stripos = false == false
882find "aBCdefg" in "a%CC%8ABC" - grapheme_stripos = false == false
883find "Defghijklmnopq" in "aBC" - grapheme_stripos = false == false
884find "Ab" in "abC" - grapheme_stripos = 0 == 0
885find "bc" in "aBC" - grapheme_stripos = 1 == 1
886find "Abc" in "abC" - grapheme_stripos = 0 == 0
887find "aBcd" in "abC" - grapheme_stripos = false == false
888find "ab" in "ABc" - grapheme_stripos from 0 = 0 == 0
889find "abC" in "aBc" - grapheme_stripos from 0 = 0 == 0
890find "aBc" in "abc" - grapheme_stripos from 1 = false == false
891find "AB" in "ABabc" - grapheme_stripos from 1 = 2 == 2
892find "AB" in "ABabc" - grapheme_stripos from -4 = 2 == 2
893find "aBc" in "abaBc" - grapheme_stripos from 1 = 2 == 2
894find "Oa%CC%8AbC" in "aoa%CC%8Abco%CC%88oA%CC%8AbC" - grapheme_stripos from 2 = 6 == 6
895find "a%CC%8ABca%CC%8A" in "o%CC%88a%CC%8AaA%CC%8AbCa%CC%8Adef" - grapheme_stripos from 2 = 3 == 3
896
897function grapheme_strrpos($haystack, $needle, $offset = 0) {}
898
899find "o" in "aa%CC%8Abco%CC%88o" - grapheme_strrpos = 5 == 5
900find "o" in "aa%CC%8Abco%CC%88" - grapheme_strrpos = false == false
901find "o%CC%88" in "aa%CC%8Abco%CC%88" - grapheme_strrpos = 4 == 4
902find "a%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_strrpos = 2 == 2
903find "a%CC%8A" in "aa%CC%8Abc" - grapheme_strrpos = 1 == 1
904find "a%CC%8A" in "abc" - grapheme_strrpos = false == false
905find "a" in "a%CC%8Abc" - grapheme_strrpos = false == false
906find "d" in "abc" - grapheme_strrpos = false == false
907find "c" in "abc" - grapheme_strrpos = 2 == 2
908find "b" in "abc" - grapheme_strrpos = 1 == 1
909find "a" in "abc" - grapheme_strrpos = 0 == 0
910find "a" in "abc" - grapheme_strrpos from 0 = 0 == 0
911find "a" in "abc" - grapheme_strrpos from 1 = false == false
912find "a" in "ababc" - grapheme_strrpos from 1 = 2 == 2
913find "o" in "aoa%CC%8Abco%CC%88o" - grapheme_strrpos from 2 = 6 == 6
914find "a%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abc" - grapheme_strrpos from 2 = 3 == 3
915find "op" in "aa%CC%8Abco%CC%88opq" - grapheme_strrpos = 5 == 5
916find "opq" in "aa%CC%8Abco%CC%88opq" - grapheme_strrpos = 5 == 5
917find "abc" in "aa%CC%8Abco%CC%88" - grapheme_strrpos = false == false
918find "o%CC%88bco%CC%88" in "aa%CC%8Abco%CC%88bco%CC%88" - grapheme_strrpos = 4 == 4
919find "a%CC%8Abc" in "o%CC%88aa%CC%8Abc" - grapheme_strrpos = 2 == 2
920find "a%CC%8Abc" in "aa%CC%8Abc" - grapheme_strrpos = 1 == 1
921find "a%CC%8Abc" in "abc" - grapheme_strrpos = false == false
922find "abcdefg" in "a%CC%8Abc" - grapheme_strrpos = false == false
923find "defghijklmnopq" in "abc" - grapheme_strrpos = false == false
924find "ab" in "abc" - grapheme_strrpos = 0 == 0
925find "bc" in "abc" - grapheme_strrpos = 1 == 1
926find "abc" in "abc" - grapheme_strrpos = 0 == 0
927find "abcd" in "abc" - grapheme_strrpos = false == false
928find "ab" in "abc" - grapheme_strrpos from 0 = 0 == 0
929find "abc" in "abc" - grapheme_strrpos from 0 = 0 == 0
930find "abc" in "abc" - grapheme_strrpos from 1 = false == false
931find "ab" in "ababc" - grapheme_strrpos from 1 = 2 == 2
932find "abc" in "ababc" - grapheme_strrpos from 1 = 2 == 2
933find "oa%CC%8Abc" in "aoa%CC%8Abco%CC%88oa%CC%8Abc" - grapheme_strrpos from 2 = 6 == 6
934find "a%CC%8Abca%CC%8A" in "o%CC%88a%CC%8Aaa%CC%8Abca%CC%8Adef" - grapheme_strrpos from 2 = 3 == 3
935
936function grapheme_strripos($haystack, $needle, $offset = 0) {}
937
938find "o" in "aoa%CC%8Abco%CC%88O" - grapheme_strripos from 2 = 6 == 6
939find "a%CC%8A" in "o%CC%88a%CC%8AaA%CC%8Abc" - grapheme_strripos from 2 = 3 == 3
940find "o" in "aa%CC%8Abco%CC%88O" - grapheme_strripos = 5 == 5
941find "O" in "aa%CC%8Abco%CC%88" - grapheme_strripos = false == false
942find "o%CC%88" in "aa%CC%8AbcO%CC%88" - grapheme_strripos = 4 == 4
943find "A%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_strripos = 2 == 2
944find "a%CC%8A" in "aA%CC%8Abc" - grapheme_strripos = 1 == 1
945find "a%CC%8A" in "Abc" - grapheme_strripos = false == false
946find "A" in "a%CC%8Abc" - grapheme_strripos = false == false
947find "D" in "abc" - grapheme_strripos = false == false
948find "c" in "abC" - grapheme_strripos = 2 == 2
949find "B" in "abc" - grapheme_strripos = 1 == 1
950find "a" in "Abc" - grapheme_strripos = 0 == 0
951find "A" in "abc" - grapheme_strripos from 0 = 0 == 0
952find "a" in "Abc" - grapheme_strripos from 1 = false == false
953find "A" in "ababc" - grapheme_strripos from 1 = 2 == 2
954find "oP" in "aa%CC%8Abco%CC%88Opq" - grapheme_strripos = 5 == 5
955find "opQ" in "aa%CC%8Abco%CC%88Opq" - grapheme_strripos = 5 == 5
956find "abc" in "aa%CC%8Abco%CC%88" - grapheme_strripos = false == false
957find "O%CC%88bco%CC%88" in "aa%CC%8Abco%CC%88bCo%CC%88" - grapheme_strripos = 4 == 4
958find "A%CC%8Abc" in "o%CC%88aa%CC%8ABc" - grapheme_strripos = 2 == 2
959find "a%CC%8Abc" in "aa%CC%8ABC" - grapheme_strripos = 1 == 1
960find "a%CC%8ABC" in "abc" - grapheme_strripos = false == false
961find "aBCdefg" in "a%CC%8ABC" - grapheme_strripos = false == false
962find "Defghijklmnopq" in "aBC" - grapheme_strripos = false == false
963find "Ab" in "abC" - grapheme_strripos = 0 == 0
964find "bc" in "aBC" - grapheme_strripos = 1 == 1
965find "Abc" in "abC" - grapheme_strripos = 0 == 0
966find "aBcd" in "abC" - grapheme_strripos = false == false
967find "ab" in "ABc" - grapheme_strripos from 0 = 0 == 0
968find "abC" in "aBc" - grapheme_strripos from 0 = 0 == 0
969find "aBc" in "abc" - grapheme_strripos from 1 = false == false
970find "AB" in "ABabc" - grapheme_strripos from 1 = 2 == 2
971find "aBc" in "abaBc" - grapheme_strripos from 1 = 2 == 2
972find "Oa%CC%8AbC" in "aoa%CC%8Abco%CC%88oA%CC%8AbC" - grapheme_strripos from 2 = 6 == 6
973find "a%CC%8ABca%CC%8A" in "o%CC%88a%CC%8AaA%CC%8AbCa%CC%8Adef" - grapheme_strripos from 2 = 3 == 3
974
975function grapheme_substr($string, $start, $length = -1) {}
976
977substring of "abc" from "3" - grapheme_substr =  ==
978substring of "aa%CC%8Abco%CC%88" from "5" - grapheme_substr =  ==
979substring of "aoa%CC%8Abco%CC%88O" from "2" - grapheme_substr = a%CC%8Abco%CC%88O == a%CC%8Abco%CC%88O
980substring of "o%CC%88a%CC%8AaA%CC%8Abc" from "2" - grapheme_substr = aA%CC%8Abc == aA%CC%8Abc
981substring of "aa%CC%8Abco%CC%88O" from "5" - grapheme_substr = O == O
982substring of "aa%CC%8Abco%CC%88" from "5" - grapheme_substr =  ==
983substring of "aa%CC%8AbcO%CC%88" from "4" - grapheme_substr = O%CC%88 == O%CC%88
984substring of "o%CC%88aa%CC%8Abc" from "2" - grapheme_substr = a%CC%8Abc == a%CC%8Abc
985substring of "aA%CC%8Abc" from "1" - grapheme_substr = A%CC%8Abc == A%CC%8Abc
986substring of "Abc" from "-5" - grapheme_substr = Abc == Abc
987substring of "a%CC%8Abc" from "3" - grapheme_substr =  ==
988substring of "abc" from "4" - grapheme_substr =  ==
989substring of "abC" from "2" - grapheme_substr = C == C
990substring of "abc" from "1" - grapheme_substr = bc == bc
991substring of "Abc" from "1" - grapheme_substr with length 1 = b == b
992substring of "abc" from "0" - grapheme_substr with length 2 = ab == ab
993substring of "Abc" from "-4" - grapheme_substr with length 1 = A == A
994substring of "ababc" from "1" - grapheme_substr with length 2 = ba == ba
995substring of "ababc" from "0" - grapheme_substr with length 10 = ababc == ababc
996substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length 10 = aa%CC%8Abco%CC%88Opq == aa%CC%8Abco%CC%88Opq
997substring of "aa%CC%8Abco%CC%88Opq" from "5" - grapheme_substr = Opq == Opq
998substring of "aa%CC%8Abco%CC%88Opq" from "5" - grapheme_substr with length -1 = Op == Op
999substring of "aa%CC%8Abco%CC%88Opq" from "5" - grapheme_substr with length -2 = O == O
1000substring of "aa%CC%8Abco%CC%88Opq" from "5" - grapheme_substr with length -3 =  ==
1001substring of "aa%CC%8Abco%CC%88Opq" from "5" - grapheme_substr with length -4 =  ==
1002substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr = aa%CC%8Abco%CC%88Opq == aa%CC%8Abco%CC%88Opq
1003substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -1 = aa%CC%8Abco%CC%88Op == aa%CC%8Abco%CC%88Op
1004substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -2 = aa%CC%8Abco%CC%88O == aa%CC%8Abco%CC%88O
1005substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -3 = aa%CC%8Abco%CC%88 == aa%CC%8Abco%CC%88
1006substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -4 = aa%CC%8Abc == aa%CC%8Abc
1007substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -5 = aa%CC%8Ab == aa%CC%8Ab
1008substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -6 = aa%CC%8A == aa%CC%8A
1009substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -7 = a == a
1010substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -8 =  ==
1011substring of "aa%CC%8Abco%CC%88Opq" from "0" - grapheme_substr with length -9 =  ==
1012substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr = aa%CC%8Abco%CC%88Opq == aa%CC%8Abco%CC%88Opq
1013substring of "aa%CC%8Abco%CC%88Opq" from "-7" - grapheme_substr = a%CC%8Abco%CC%88Opq == a%CC%8Abco%CC%88Opq
1014substring of "aa%CC%8Abco%CC%88Opq" from "-6" - grapheme_substr = bco%CC%88Opq == bco%CC%88Opq
1015substring of "aa%CC%8Abco%CC%88Opq" from "-5" - grapheme_substr = co%CC%88Opq == co%CC%88Opq
1016substring of "aa%CC%8Abco%CC%88Opq" from "-4" - grapheme_substr = o%CC%88Opq == o%CC%88Opq
1017substring of "aa%CC%8Abco%CC%88Opq" from "-3" - grapheme_substr = Opq == Opq
1018substring of "aa%CC%8Abco%CC%88Opq" from "-2" - grapheme_substr = pq == pq
1019substring of "aa%CC%8Abco%CC%88Opq" from "-1" - grapheme_substr = q == q
1020substring of "aa%CC%8Abco%CC%88Opq" from "-999" - grapheme_substr = aa%CC%8Abco%CC%88Opq == aa%CC%8Abco%CC%88Opq
1021substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 8 = aa%CC%8Abco%CC%88Opq == aa%CC%8Abco%CC%88Opq
1022substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 7 = aa%CC%8Abco%CC%88Op == aa%CC%8Abco%CC%88Op
1023substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 6 = aa%CC%8Abco%CC%88O == aa%CC%8Abco%CC%88O
1024substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 5 = aa%CC%8Abco%CC%88 == aa%CC%8Abco%CC%88
1025substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 4 = aa%CC%8Abc == aa%CC%8Abc
1026substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 3 = aa%CC%8Ab == aa%CC%8Ab
1027substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 2 = aa%CC%8A == aa%CC%8A
1028substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 1 = a == a
1029substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length 0 =  ==
1030substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -999 =  ==
1031substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -1 = aa%CC%8Abco%CC%88Op == aa%CC%8Abco%CC%88Op
1032substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -2 = aa%CC%8Abco%CC%88O == aa%CC%8Abco%CC%88O
1033substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -3 = aa%CC%8Abco%CC%88 == aa%CC%8Abco%CC%88
1034substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -4 = aa%CC%8Abc == aa%CC%8Abc
1035substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -5 = aa%CC%8Ab == aa%CC%8Ab
1036substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -6 = aa%CC%8A == aa%CC%8A
1037substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -7 = a == a
1038substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -8 =  ==
1039substring of "aa%CC%8Abco%CC%88Opq" from "-8" - grapheme_substr with length -9 =  ==
1040
1041function grapheme_strstr($haystack, $needle, $before_needle = FALSE) {}
1042
1043find "o" in "aa%CC%8Abco%CC%88o" - grapheme_strstr = o == o
1044find "o" in "aa%CC%8Abco%CC%88" - grapheme_strstr = false == false
1045find "o%CC%88" in "aa%CC%8Abco%CC%88" - grapheme_strstr = o%CC%88 == o%CC%88
1046find "a%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_strstr = a%CC%8Abc == a%CC%8Abc
1047find "a%CC%8A" in "aa%CC%8Abc" - grapheme_strstr = a%CC%8Abc == a%CC%8Abc
1048find "a%CC%8A" in "abc" - grapheme_strstr = false == false
1049find "a" in "a%CC%8Abc" - grapheme_strstr = false == false
1050find "d" in "abc" - grapheme_strstr = false == false
1051find "c" in "abc" - grapheme_strstr = c == c
1052find "b" in "abc" - grapheme_strstr = bc == bc
1053find "a" in "abc" - grapheme_strstr = abc == abc
1054find "ab" in "abc" - grapheme_strstr = abc == abc
1055find "abc" in "abc" - grapheme_strstr = abc == abc
1056find "bc" in "abc" - grapheme_strstr = bc == bc
1057find "a" in "abc" - grapheme_strstr before flag is FALSE = abc == abc
1058find "a" in "abc" - grapheme_strstr before flag is TRUE =  ==
1059find "b" in "abc" - grapheme_strstr before flag is TRUE = a == a
1060find "c" in "abc" - grapheme_strstr before flag is TRUE = ab == ab
1061find "bab" in "ababc" - grapheme_strstr before flag is TRUE = a == a
1062find "abc" in "ababc" - grapheme_strstr before flag is TRUE = ab == ab
1063find "abc" in "ababc" - grapheme_strstr before flag is FALSE = abc == abc
1064find "d" in "aba%CC%8Ac" - grapheme_strstr = false == false
1065find "a" in "bca%CC%8Aa" - grapheme_strstr = a == a
1066find "b" in "aa%CC%8Abc" - grapheme_strstr = bc == bc
1067find "a" in "a%CC%8Abc" - grapheme_strstr = false == false
1068find "ab" in "a%CC%8Aabc" - grapheme_strstr = abc == abc
1069find "abc" in "abca%CC%8A" - grapheme_strstr = abca%CC%8A == abca%CC%8A
1070find "a%CC%8Abc" in "aa%CC%8Abc" - grapheme_strstr = a%CC%8Abc == a%CC%8Abc
1071find "a%CC%8A" in "aa%CC%8Abc" - grapheme_strstr before flag is FALSE = a%CC%8Abc == a%CC%8Abc
1072find "a" in "aa%CC%8Abc" - grapheme_strstr before flag is TRUE =  ==
1073find "b" in "a%CC%8Aabc" - grapheme_strstr before flag is TRUE = a%CC%8Aa == a%CC%8Aa
1074find "c" in "aba%CC%8Ac" - grapheme_strstr before flag is TRUE = aba%CC%8A == aba%CC%8A
1075find "baa%CC%8Ab" in "abaa%CC%8Abc" - grapheme_strstr before flag is TRUE = a == a
1076find "abca%CC%8A" in "ababca%CC%8A" - grapheme_strstr before flag is TRUE = ab == ab
1077find "aba%CC%8Ac" in "ababa%CC%8Ac" - grapheme_strstr before flag is FALSE = aba%CC%8Ac == aba%CC%8Ac
1078
1079function grapheme_stristr($haystack, $needle, $before_needle = FALSE) {}
1080
1081find "O%CC%88" in "aa%CC%8Abco%CC%88" - grapheme_stristr = o%CC%88 == o%CC%88
1082find "o" in "aa%CC%8Abco%CC%88O" - grapheme_stristr = O == O
1083find "o" in "aa%CC%8Abco%CC%88" - grapheme_stristr = false == false
1084find "a%CC%8A" in "o%CC%88aa%CC%8Abc" - grapheme_stristr = a%CC%8Abc == a%CC%8Abc
1085find "A%CC%8A" in "aa%CC%8Abc" - grapheme_stristr = a%CC%8Abc == a%CC%8Abc
1086find "a%CC%8A" in "abc" - grapheme_stristr = false == false
1087find "A" in "a%CC%8Abc" - grapheme_stristr = false == false
1088find "d" in "abc" - grapheme_stristr = false == false
1089find "C" in "abc" - grapheme_stristr = c == c
1090find "b" in "aBc" - grapheme_stristr = Bc == Bc
1091find "A" in "abc" - grapheme_stristr = abc == abc
1092find "ab" in "abC" - grapheme_stristr = abC == abC
1093find "aBc" in "abc" - grapheme_stristr = abc == abc
1094find "bc" in "abC" - grapheme_stristr = bC == bC
1095find "A" in "abc" - grapheme_stristr before flag is FALSE = abc == abc
1096find "a" in "abc" - grapheme_stristr before flag is TRUE =  ==
1097find "b" in "aBc" - grapheme_stristr before flag is TRUE = a == a
1098find "C" in "abc" - grapheme_stristr before flag is TRUE = ab == ab
1099find "bab" in "aBabc" - grapheme_stristr before flag is TRUE = a == a
1100find "aBc" in "ababc" - grapheme_stristr before flag is TRUE = ab == ab
1101find "abC" in "ababc" - grapheme_stristr before flag is FALSE = abc == abc
1102find "d" in "aba%CC%8Ac" - grapheme_stristr = false == false
1103find "a" in "bca%CC%8AA" - grapheme_stristr = A == A
1104find "B" in "aa%CC%8Abc" - grapheme_stristr = bc == bc
1105find "a" in "A%CC%8Abc" - grapheme_stristr = false == false
1106find "Ab" in "a%CC%8Aabc" - grapheme_stristr = abc == abc
1107find "abc" in "abcA%CC%8A" - grapheme_stristr = abcA%CC%8A == abcA%CC%8A
1108find "A%CC%8Abc" in "aa%CC%8Abc" - grapheme_stristr = a%CC%8Abc == a%CC%8Abc
1109find "a%CC%8A" in "aA%CC%8Abc" - grapheme_stristr before flag is FALSE = A%CC%8Abc == A%CC%8Abc
1110find "A" in "aa%CC%8Abc" - grapheme_stristr before flag is TRUE =  ==
1111find "b" in "a%CC%8AaBc" - grapheme_stristr before flag is TRUE = a%CC%8Aa == a%CC%8Aa
1112find "C" in "aba%CC%8Ac" - grapheme_stristr before flag is TRUE = aba%CC%8A == aba%CC%8A
1113find "baa%CC%8Ab" in "abaA%CC%8Abc" - grapheme_stristr before flag is TRUE = a == a
1114find "aBcA%CC%8A" in "ababca%CC%8A" - grapheme_stristr before flag is TRUE = ab == ab
1115find "aba%CC%8Ac" in "abABA%CC%8Ac" - grapheme_stristr before flag is FALSE = ABA%CC%8Ac == ABA%CC%8Ac
1116
1117function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_COUNT, $start = 0[, $next])
1118
1119extract from "abc" "3" graphemes - grapheme_extract = abc == abc
1120extract from "abc" "2" graphemes - grapheme_extract = ab == ab
1121extract from "abc" "1" graphemes - grapheme_extract = a == a
1122extract from "abc" "0" graphemes - grapheme_extract =  ==
1123extract from "abc" "1" graphemes - grapheme_extract starting at byte position 0 = a == a
1124extract from "abc" "1" graphemes - grapheme_extract starting at byte position 1 = b == b
1125extract from "abc" "1" graphemes - grapheme_extract starting at byte position 2 = c == c
1126extract from "abc" "0" graphemes - grapheme_extract starting at byte position 2 =  ==
1127extract from "abc" "3" graphemes - grapheme_extract starting at byte position 0 with $next = abc == abc $next=3 == 3
1128extract from "abc" "2" graphemes - grapheme_extract starting at byte position 0 with $next = ab == ab $next=2 == 2
1129extract from "abc" "1" graphemes - grapheme_extract starting at byte position 0 with $next = a == a $next=1 == 1
1130extract from "abc" "0" graphemes - grapheme_extract starting at byte position 0 with $next =  ==  $next=0 == 0
1131extract from "abc" "1" graphemes - grapheme_extract starting at byte position 0 with $next = a == a $next=1 == 1
1132extract from "abc" "1" graphemes - grapheme_extract starting at byte position 1 with $next = b == b $next=2 == 2
1133extract from "abc" "1" graphemes - grapheme_extract starting at byte position 2 with $next = c == c $next=3 == 3
1134extract from "abc" "1" graphemes - grapheme_extract starting at byte position -2 with $next = b == b $next=2 == 2
1135extract from "abc" "0" graphemes - grapheme_extract starting at byte position 2 with $next =  ==  $next=2 == 2
1136extract 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
1137extract from "a%CC%8Abc" "3" graphemes - grapheme_extract = a%CC%8Abc == a%CC%8Abc
1138extract from "a%CC%8Abc" "2" graphemes - grapheme_extract = a%CC%8Ab == a%CC%8Ab
1139extract from "a%CC%8Abc" "1" graphemes - grapheme_extract = a%CC%8A == a%CC%8A
1140extract from "a%CC%8Abc" "3" graphemes - grapheme_extract starting at byte position 0 with $next = a%CC%8Abc == a%CC%8Abc $next=5 == 5
1141extract from "a%CC%8Abc" "2" graphemes - grapheme_extract starting at byte position 0 with $next = a%CC%8Ab == a%CC%8Ab $next=4 == 4
1142extract from "a%CC%8Abc" "1" graphemes - grapheme_extract starting at byte position 0 with $next = a%CC%8A == a%CC%8A $next=3 == 3
1143extract from "a%CC%8Abcde" "2" graphemes - grapheme_extract starting at byte position 3 with $next = bc == bc $next=5 == 5
1144extract from "a%CC%8Abcde" "2" graphemes - grapheme_extract starting at byte position -4 with $next = bc == bc $next=5 == 5
1145extract from "a%CC%8Abcde" "2" graphemes - grapheme_extract starting at byte position 4 with $next = cd == cd $next=6 == 6
1146extract from "a%CC%8Abcde" "2" graphemes - grapheme_extract starting at byte position -7 with $next = a%CC%8Ab == a%CC%8Ab $next=4 == 4
1147extract 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
1148extract 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
1149extract 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
1150extract from "a%CC%8Ao%CC%88o%CC%88" "2" graphemes - grapheme_extract = a%CC%8Ao%CC%88 == a%CC%8Ao%CC%88
1151extract from "a%CC%8Ao%CC%88c" "1" graphemes - grapheme_extract = a%CC%8A == a%CC%8A
1152extract 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
1153extract 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
1154extract 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
1155extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "1" graphemes - grapheme_extract starting at byte position 4 = %CC%88 == %CC%88
1156extract 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
1157extract 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
1158extract 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
1159extract 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
1160extract 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
1161extract 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
1162extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract starting at byte position 10 = %CC%88 == %CC%88
1163extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract starting at byte position 11 = false == false
1164
1165function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_MAXBYTES, $start = 0)
1166
1167extract from "abc" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = abc == abc
1168extract from "abc" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = ab == ab
1169extract from "abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a == a
1170extract from "abc" "0" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES =  ==
1171extract from "a%CC%8Abc" "5" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8Abc == a%CC%8Abc
1172extract from "a%CC%8Abc" "4" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8Ab == a%CC%8Ab
1173extract from "a%CC%8Abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES =  ==
1174extract 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
1175extract 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
1176extract 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
1177extract 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
1178extract from "a%CC%8Ao%CC%88c" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8A == a%CC%8A
1179extract from "a%CC%8Ao%CC%88c" "4" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8A == a%CC%8A
1180extract from "a%CC%8Ao%CC%88c" "5" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8A == a%CC%8A
1181extract from "a%CC%8Ao%CC%88c" "6" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8Ao%CC%88 == a%CC%8Ao%CC%88
1182extract from "a%CC%8Ao%CC%88c" "7" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES = a%CC%8Ao%CC%88c == a%CC%8Ao%CC%88c
1183extract 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
1184extract 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
1185extract 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
1186extract 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
1187extract 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
1188extract 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
1189extract 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
1190extract 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
1191extract 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
1192extract 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
1193extract 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
1194extract from "o%CC%88o%CC%88o%CC%88o%CC%88" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXBYTES starting at byte position 11 = false == false
1195
1196function grapheme_extract($haystack, $size, $extract_type = GRAPHEME_EXTR_MAXCHARS, $start = 0)
1197
1198extract from "abc" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = abc == abc
1199extract from "abc" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = ab == ab
1200extract from "abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = a == a
1201extract from "abc" "0" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS =  ==
1202extract from "abco%CC%88" "0" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS =  ==
1203extract from "abco%CC%88" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = a == a
1204extract from "abco%CC%88" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = ab == ab
1205extract from "abco%CC%88" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = abc == abc
1206extract from "abco%CC%88" "4" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = abc == abc
1207extract from "abco%CC%88" "5" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = abco%CC%88 == abco%CC%88
1208extract from "abco%CC%88" "6" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = abco%CC%88 == abco%CC%88
1209extract from "o%CC%88abc" "0" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS =  ==
1210extract from "o%CC%88abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS =  ==
1211extract from "o%CC%88abc" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88 == o%CC%88
1212extract from "o%CC%88abc" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88a == o%CC%88a
1213extract from "o%CC%88abc" "4" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88ab == o%CC%88ab
1214extract from "o%CC%88abca%CC%8Axyz" "5" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88abc == o%CC%88abc
1215extract from "o%CC%88abca%CC%8Axyz" "6" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88abc == o%CC%88abc
1216extract from "o%CC%88abca%CC%8Axyz" "7" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88abca%CC%8A == o%CC%88abca%CC%8A
1217extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS = o%CC%88abca%CC%8Ax == o%CC%88abca%CC%8Ax
1218extract from "abc" "3" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 0 = abc == abc
1219extract from "abc" "2" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 1 = bc == bc
1220extract from "abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 2 = c == c
1221extract from "abc" "0" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 3 = false == false
1222extract from "abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 3 = false == false
1223extract from "abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 999 = false == false
1224extract from "o%CC%88abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 6 = false == false
1225extract from "o%CC%88abc" "1" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 999 = false == false
1226extract 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
1227extract 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
1228extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 2 = abca%CC%8Axyz == abca%CC%8Axyz
1229extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 3 = abca%CC%8Axyz == abca%CC%8Axyz
1230extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 4 = bca%CC%8Axyz == bca%CC%8Axyz
1231extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 5 = ca%CC%8Axyz == ca%CC%8Axyz
1232extract from "o%CC%88abca%CC%8Axyz" "8" graphemes - grapheme_extract GRAPHEME_EXTR_MAXCHARS starting at byte position 6 = a%CC%8Axyz == a%CC%8Axyz
1233