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