1 module java.lang.String;
2 
3 import java.lang.util;
4 import java.lang.interfaces;
5 import java.lang.exceptions;
6 import java.lang.Class;
7 
8 version(Tango){
9     static import tango.stdc.stringz;
10     static import tango.text.Util;
11     static import tango.text.Unicode;
12     static import tango.text.convert.Utf;
13 } else { // Phobos
14     static import std.array;
15     static import std..string;
16     static import std.conv;
17     static import std.exception;
18 }
19 
20 alias TryImmutable!(char)[]  String;
21 alias TryImmutable!(wchar)[] String16;
22 
23 String new_String( String cont, int offset, int len ){
24     return _idup(cont[ offset .. offset+len ]);
25 }
26 
27 String new_String( String cont ){
28     return _idup(cont);
29 }
30 
31 String String_valueOf( bool v ){
32     return v ? "true" : "false";
33 }
34 
35 String String_valueOf( byte v ){
36     return String_valueOf( cast(long) v );
37 }
38 
39 String String_valueOf( ubyte v ){
40     return String_valueOf( cast(uint) v );
41 }
42 
43 String String_valueOf( short v ){
44     return String_valueOf( cast(long) v );
45 }
46 
47 String String_valueOf( int v ){
48     return String_valueOf( cast(long) v );
49 }
50 
51 String String_valueOf( uint v ){
52     version(Tango){
53         return tango.text.convert.Integer.toString(v);
54     } else { // Phobos
55         return std.conv.to!(String)(v);
56     }
57 }
58 
59 String String_valueOf( long v ){
60     version(Tango){
61         return tango.text.convert.Integer.toString(v);
62     } else { // Phobos
63         return std.conv.to!(String)(v);
64     }
65 }
66 
67 String String_valueOf( float v ){
68     version(Tango){
69         return tango.text.convert.Float.toString(v);
70     } else { // Phobos
71         return std.conv.to!(String)(v);
72     }
73 }
74 
75 String String_valueOf( double v ){
76     version(Tango){
77         return tango.text.convert.Float.toString(v);
78     } else { // Phobos
79         return std.conv.to!(String)(v);
80     }
81 }
82 
83 String String_valueOf( dchar v ){
84     version(Tango){
85         dchar[1] buf = v;
86         return tango.text.convert.Utf.toString( buf );
87     } else { // Phobos
88         return std.conv.to!(String)(v);
89     }
90 }
91 
92 String dcharToString( dchar v ){
93     return String_valueOf(v);
94 }
95 
96 String String_valueOf( char[] v ){
97     return _idup(v);
98 }
99 
100 String String_valueOf( char[] v, int offset, int len ){
101     return _idup(v[ offset .. offset+len ]);
102 }
103 
104 String String_valueOf( Object v ){
105     return v is null ? "null" : v.toString();
106 }
107 
108 String String_valueOf( in wchar[] wstr ){
109     version(Tango){
110         return tango.text.convert.Utf.toString(wstr);
111     } else { // Phobos
112         return std.conv.to!(String)(wstr);
113     }
114 }
115 
116 int length( String str ){
117     return cast(int)/*64bit*/str.length;
118 }
119 
120 /// Extension to String
121 public String toUpperCase( String str ){
122     version(Tango){
123         return tango.text.Unicode.toUpper( str );
124     } else { // Phobos
125         return cast(String) std..string.toUpper( str );
126     }
127 }
128 
129 /// Extension to String
130 public String replaceFirst( String str, String regex, String replacement ){
131     implMissing(__FILE__,__LINE__);
132     return null;
133 }
134 
135 version(Tango) int tangoToJavaIdx(T)(int idx, T[] arr) {
136     return idx is arr.length ? -1 : idx;
137 }
138 
139 /// Extension to String
140 public int indexOf( in char[] str, char searched ){
141     version(Tango){
142         return tangoToJavaIdx(tango.text.Util.locate( str, searched ), str);
143     } else { // Phobos
144         return cast(int)/*64bit*/std..string.indexOf(str, searched);
145     }
146 }
147 
148 /// Extension to String
149 public int indexOf( in char[] str, char searched, int fromIndex ){
150     if(fromIndex >= str.length)
151         return -1;
152     version(Tango){
153         return tangoToJavaIdx(tango.text.Util.locate( str, searched, fromIndex ), str);
154     } else { // Phobos
155         int res = cast(int)/*64bit*/std..string.indexOf(str[fromIndex .. $], searched);
156         if (res !is -1) res += fromIndex;
157         return res;
158     }
159 }
160 
161 /// Extension to String
162 public int indexOf(in char[] str, in char[] sub){
163     return indexOf( str, sub, 0 );
164 }
165 
166 /// Extension to String
167 public int indexOf(in char[] str, in char[] sub, int fromIndex){
168     if(fromIndex + sub.length > str.length)
169         return -1;
170     if(!sub.length)
171         return fromIndex;
172     version(Tango){
173         return tangoToJavaIdx(tango.text.Util.locatePattern( str, sub, fromIndex ), str);
174     } else { // Phobos
175         int res = cast(int)/*64bit*/std..string.indexOf(str[fromIndex .. $], sub);
176         if (res !is -1) res += fromIndex;
177         return res;
178     }
179 }
180 
181 /// Extension to String
182 public int lastIndexOf(in char[] str, char ch){
183     return lastIndexOf( str, ch, cast(int)/*64bit*/str.length - 1 );
184 }
185 
186 /// Extension to String
187 public int lastIndexOf(in char[] str, char ch, int fromIndex){
188     if(fromIndex >= str.length)
189         fromIndex = cast(int)/*64bit*/str.length - 1;
190     version(Tango){
191         return tangoToJavaIdx(tango.text.Util.locatePrior( str, ch, fromIndex + 1 ), str);
192     } else { // Phobos
193         return cast(int)/*64bit*/std..string.lastIndexOf(str[0 .. fromIndex + 1], ch);
194     }
195 }
196 
197 /// Extension to String
198 public int lastIndexOf(in char[] str, in char[] sub ){
199     return lastIndexOf( str, sub, cast(int)/*64bit*/(str.length - sub.length) );
200 }
201 
202 /// Extension to String
203 public int lastIndexOf(in char[] str, in char[] sub, int fromIndex){
204     int max = cast(int)str.length - cast(int)sub.length;
205     if(fromIndex > max)
206         fromIndex = max;
207     if(!sub.length)
208         return fromIndex;
209     version(Tango){
210         return tangoToJavaIdx(tango.text.Util.locatePatternPrior( str, sub, fromIndex + 1 ), str);
211     } else { // Phobos
212         size_t to = fromIndex + sub.length;
213         return cast(int)/*64bit*/std..string.lastIndexOf(str[0 .. to < $ ? to : $], sub);
214     }
215 }
216 
217 unittest {
218     sizediff_t i;
219 
220     i = lastIndexOf("", 'a');
221     assert(i == -1);
222     i = lastIndexOf("def", 'a');
223     assert(i == -1);
224     i = lastIndexOf("abba", 'a');
225     assert(i == 3);
226     i = lastIndexOf("abba", 'a', 0);
227     assert(i == 0);
228     i = lastIndexOf("abba", 'a', 1);
229     assert(i == 0);
230     i = lastIndexOf("abba", 'a', 2);
231     assert(i == 0);
232     i = lastIndexOf("abba", 'a', 3);
233     assert(i == 3);
234     i = lastIndexOf("abba", 'a', 4);
235     assert(i == 3);
236     i = lastIndexOf("abba", 'a', 10);
237     assert(i == 3);
238     i = lastIndexOf("def", 'f');
239     assert(i == 2);
240 
241     i = lastIndexOf("", "a");
242     assert(i == -1);
243     i = lastIndexOf("", "");
244     assert(i == 0);
245     i = lastIndexOf("abcdefcdef", "c");
246     assert(i == 6);
247     i = lastIndexOf("abcdefcdef", "cd");
248     assert(i == 6);
249     i = lastIndexOf("abcdefcdef", "cd", 5);
250     assert(i == 2);
251     i = lastIndexOf("abcdefcdef", "cd", 6);
252     assert(i == 6);
253     i = lastIndexOf("abcdefcdef", "cd", 7);
254     assert(i == 6);
255     i = lastIndexOf("abcdefcdef", "cd", 10);
256     assert(i == 6);
257     i = lastIndexOf("abcdefcdef", "x");
258     assert(i == -1);
259     i = lastIndexOf("abcdefcdef", "xy");
260     assert(i == -1);
261     i = lastIndexOf("abcdefcdef", "");
262     assert(i == 10);
263     i = lastIndexOf("abcdefcdef", "", 9);
264     assert(i == 9);
265     i = lastIndexOf("abcabc", "abc");
266     assert(i == 3);
267     i = lastIndexOf("abcabc", "abc", 2);
268     assert(i == 0);
269     i = lastIndexOf("abcabc", "abc", 3);
270     assert(i == 3);
271     i = lastIndexOf("abcabc", "abc", 4);
272     assert(i == 3);
273 
274 
275 
276     i = indexOf("", 'a');
277     assert(i == -1);
278     i = indexOf("def", 'a');
279     assert(i == -1);
280     i = indexOf("abba", 'a');
281     assert(i == 0);
282     i = indexOf("abba", 'a', 0);
283     assert(i == 0);
284     i = indexOf("abba", 'a', 1);
285     assert(i == 3);
286     i = indexOf("abba", 'a', 2);
287     assert(i == 3);
288     i = indexOf("abba", 'a', 3);
289     assert(i == 3);
290     i = indexOf("abba", 'a', 4);
291     assert(i == -1);
292     i = indexOf("abba", 'a', 10);
293     assert(i == -1);
294     i = indexOf("def", 'f');
295     assert(i == 2);
296 
297     i = indexOf("", "a");
298     assert(i == -1);
299     i = indexOf("", "");
300     assert(i == 0);
301     i = indexOf("abcdefcdef", "c");
302     assert(i == 2);
303     i = indexOf("abcdefcdef", "cd");
304     assert(i == 2);
305     i = indexOf("abcdefcdef", "cd", 4);
306     assert(i == 6);
307     i = indexOf("abcdefcdef", "cd", 5);
308     assert(i == 6);
309     i = indexOf("abcdefcdef", "cd", 6);
310     assert(i == 6);
311     i = indexOf("abcdefcdef", "cd", 7);
312     assert(i == -1);
313     i = indexOf("abcdefcdef", "cd", 10);
314     assert(i == -1);
315     i = indexOf("abcdefcdef", "x");
316     assert(i == -1);
317     i = indexOf("abcdefcdef", "xy");
318     assert(i == -1);
319     i = indexOf("abcdefcdef", "");
320     assert(i == 0);
321     i = indexOf("abcabc", "abc");
322     assert(i == 0);
323     i = indexOf("abcabc", "abc", 2);
324     assert(i == 3);
325     i = indexOf("abcabc", "abc", 3);
326     assert(i == 3);
327     i = indexOf("abcabc", "abc", 4);
328     assert(i == -1);
329 }
330 
331 /// Extension to String
332 public String replaceAll( String str, String regex, String replacement ){
333     implMissing(__FILE__,__LINE__);
334     return null;
335 }
336 
337 /// Extension to String
338 public String replace( String str, char from, char to ){
339     version(Tango){
340         return tango.text.Util.replace( str.dup, from, to );
341     } else { // Phobos
342         char[1] f = from, t = to;
343         auto res = std.array.replace(str, f[], t[]);
344         return std.exception.assumeUnique(res);
345     }
346 }
347 
348 /// Extension to String
349 public String substring( String str, int start ){
350     return _idup(str[ start .. $ ]);
351 }
352 
353 /// Extension to String
354 public String substring( String str, int start, int end ){
355     return _idup(str[ start .. end ]);
356 }
357 
358 /// Extension to String
359 public wchar[] substring( String16 str, int start ){
360     return str[ start .. $ ].dup;
361 }
362 
363 /// Extension to String
364 public wchar[] substring( String16 str, int start, int end ){
365     return str[ start .. end ].dup;
366 }
367 
368 /// Extension to String
369 public char charAt( String str, int pos ){
370     return str[ pos ];
371 }
372 
373 /// Extension to String
374 public void getChars( String src, int srcBegin, int srcEnd, char[] dst, int dstBegin){
375     dst[ dstBegin .. dstBegin + srcEnd - srcBegin ] = src[ srcBegin .. srcEnd ];
376 }
377 
378 /// Extension to String
379 public String16 toWCharArray( in char[] str ){
380     version(Tango){
381         return tango.text.convert.Utf.toString16(str);
382     } else { // Phobos
383         return std.conv.to!(String16)(str);
384     }
385 }
386 
387 /// Extension to String
388 public char[] toCharArray( String str ){
389     return cast(char[])str;
390 }
391 
392 /// Extension to String
393 public bool endsWith( String src, String pattern ){
394     if( src.length < pattern.length ){
395         return false;
396     }
397     return src[ $-pattern.length .. $ ] == pattern;
398 }
399 
400 /// Extension to String
401 public bool equals( in char[] src, in char[] other ){
402     return src == other;
403 }
404 
405 /// Extension to String
406 public bool equalsIgnoreCase( in char[] src, in char[] other ){
407     version(Tango) {
408         static assert(false, "Not implemented");
409     } else { // Phobos
410         return std..string.icmp(src, other) == 0;
411     }
412 }
413 
414 /// Extension to String
415 public int compareToIgnoreCase( in char[] src, in char[] other ){
416     version(Tango){
417         static assert(false, "Not implemented");
418     } else { // Phobos
419         return std..string.icmp(src, other);
420     }
421 }
422 
423 /// Extension to String
424 public int compareTo( in char[] src, in char[] other ){
425     version(Tango){
426         return typeid(String).compare( cast(void*)&src, cast(void*)&other );
427     } else { // Phobos
428         return std..string.cmp(src, other);
429     }
430 }
431 
432 /// Extension to String
433 public bool startsWith( String src, String pattern ){
434     if( src.length < pattern.length ){
435         return false;
436     }
437     return src[ 0 .. pattern.length ] == pattern;
438 }
439 
440 /// Extension to String
441 public String toLowerCase( String src ){
442     version(Tango){
443         return tango.text.Unicode.toLower( src );
444     } else { // Phobos
445         return cast(String) std..string.toLower(src);
446     }
447 }
448 
449 /// Extension to String
450 version(Tango){
451     public hash_t toHash( String src ){
452         return typeid(String).getHash(&src);
453     }
454 } else { // Phobos
455     mixin(`@safe nothrow public hash_t toHash( String src ){
456         // http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#hashCode%28%29
457         hash_t hash = 0;
458         foreach( i, c; src ){
459             hash += c * 31 ^ (src.length - 1 - i);
460         }
461         return hash;
462     }`);
463 }
464 public alias toHash String_toHash;
465 
466 /// Extension to String
467 public String trim( String str ){
468     version(Tango){
469         return tango.text.Util.trim( str ).dup;
470     } else { // Phobos
471         return std..string.strip( str.idup );
472     }
473 }
474 
475 /// Extension to String
476 public String intern( String str ){
477     return _idup(str);
478 }
479 
480 version(Tango){
481     public alias tango.stdc.stringz.toStringz toStringz;
482     public alias tango.stdc.stringz.toString16z toString16z;
483     public alias tango.stdc.stringz.fromStringz fromStringz;
484     public alias tango.stdc.stringz.fromString16z fromString16z;
485 
486     /++
487      + This is like tango.stdc.stringz.toStringz, but in case of an empty input string,
488      + this function returns a pointer to a null value instead of a null ptr.
489      +/
490     public char* toStringzValidPtr( String src ){
491         if( src ){
492             return src.toStringz();
493         }
494         else{
495             return "".ptr;
496         }
497     }
498 } else { // Phobos
499     static import core.stdc..string;
500 
501     public char* toStringzValidPtr( in char[] s ) {
502         auto copy = new char[s.length + 1];
503         copy[0..s.length] = s;
504         copy[s.length] = 0;
505         return copy.ptr;
506     }
507 
508     public char* toStringz( in char[] s ) {
509         return s is null ? null : toStringzValidPtr(s);
510     }
511 
512     public char[] fromStringz( in char* s ){
513         return s ? s[0 .. core.stdc..string.strlen(s)].dup : cast(char[])null;
514     }
515     /*public string fromStringz( in char* s ){
516         return std.conv.to!(string)(s);
517     }*/
518 
519     private size_t w_strlen(in wchar* s) {
520         size_t res = 0;
521         while(*(s+res))
522             ++res;
523         return res;
524     }
525 
526     public wchar* toString16z( in wchar[] s ){
527         if(s is null)
528             return null;
529         auto copy = new wchar[s.length + 1];
530         copy[0..s.length] = s;
531         copy[s.length] = 0;
532         return copy.ptr;
533     }
534 
535     //Copy of std.conv.toImpl(T, S)(S s) for C-style strings
536     public wstring fromString16z( in wchar* s ){
537         return s ? s[0 .. w_strlen(s)].idup : cast(wstring)null;
538     }
539 }
540 
541 static String toHex(uint i){
542     version(Tango){
543         return tango.text.convert.Integer.toString(i, "x");
544     } else { // Phobos
545         return std.conv.to!(String)(i, 16);
546     }
547 }
548 
549 /++
550 + String in java is implementing the interface CharSequence
551 +/
552 class StringCharSequence : CharSequence {
553     private String str;
554     this( String str ){
555         this.str = str;
556     }
557     char charAt(int index){
558         return str[index];
559     }
560     int length(){
561         return cast(int)/*64bit*/str.length;
562     }
563     CharSequence subSequence(int start, int end){
564         return new StringCharSequence( str[ start .. end ]);
565     }
566     override
567     String toString(){
568         return str;
569     }
570 }
571 
572 class StringCls {
573     private static Class TYPE_;
574     public static Class TYPE(){
575         if( TYPE_ is null ){
576             TYPE_ = Class.fromType!(char[]);
577         }
578         return TYPE_;
579     }
580 
581 }