1 /++
2 	String manipulation functions.
3 
4 	See_Also:
5 		To get a substring, you can use the built-in array slice operator.
6 
7 		For reading various encodings into a standard string, see [arsd.characterencodings].
8 
9 		For converting things to and from strings, see [arsd.conv].
10 
11 		For sorting an array of strings, see... std.algorithm for now but maybe here later.
12 
13 	History:
14 		Added May 23, 2025
15 +/
16 module arsd..string;
17 
18 static import arsd.core;
19 
20 /// Public interface to arsd.core
21 alias startsWith = arsd.core.startsWith;
22 /// ditto
23 alias endsWith = arsd.core.endsWith;
24 /// ditto
25 alias indexOf = arsd.core.indexOf;
26 
27 // replace? replaceFirst, replaceAll, replaceAny etc
28 
29 // limitSize - truncates to the last code point under the given length of code units
30 
31 /// Strips (aka trims) leading and/or trailing whitespace from the string.
32 alias strip = arsd.core.stripInternal;
33 /// ditto
34 deprecated("D calls this `strip` instead") alias trim = strip;
35 
36 /// ditto
37 alias stripRight = arsd.core.stripInternal;
38 /// ditto
39 deprecated("D calls this `stripRight` instead") alias trimRight = stripRight;
40 
41 // stripLeft? variants where you can list the chars to strip?
42 
43 // ascii to upper, to lower, capitalize words, from camel case to dash separated
44 
45 // ********* UTF **************
46 // utf8 stride and such?
47 // get the starting code unit of the given point in the string
48 // get the next code unit start after the given point (compare upstream popFront)
49 // iterate over a string putting a replacement char in any invalid utf 8 spot
50 
51 // ********* C INTEROP **************
52 
53 alias stringz = arsd.core.stringz;
54 // CharzBuffer
55 // WCharzBuffer
56 
57 // ********* UTILITIES **************
58 
59 string[] split(string s, string onWhat) {
60 	assert(onWhat.length);
61 	string[] ret;
62 	more:
63 	auto idx = s.indexOf(onWhat);
64 	if(idx == -1) {
65 		ret ~= s;
66 		return ret;
67 	}
68 	ret ~= s[0 .. idx];
69 	s = s[idx + onWhat.length .. $];
70 	goto more;
71 }
72 
73 unittest {
74 	assert("foo.bar".split(".") == ["foo", "bar"]);
75 }
76 
77 ptrdiff_t lastIndexOf(string s, string what) {
78 	assert(what.length);
79 	if(s.length < what.length)
80 		return -1;
81 	ptrdiff_t checking = s.length - what.length;
82 	while(checking >= 0) {
83 		if(s[checking .. checking + what.length] == what)
84 			return checking;
85 
86 		checking--;
87 	}
88 
89 	return -1;
90 }
91 
92 unittest {
93 	assert("31234".lastIndexOf("3") == 3);
94 }
95 
96 string join(string[] str, string w) {
97 	string ret;
98 	foreach(i, s; str) {
99 		if(i)
100 			ret ~= w;
101 		ret ~= s;
102 	}
103 	return ret;
104 }
105 
106 unittest {
107 	assert(["a", "b"].join(" ") == "a b");
108 }
109 
110 string replace(string str, string find, string repacement) {
111 	assert(find.length);
112 
113 	string ret;
114 	more:
115 	auto idx = str.indexOf(find);
116 	if(idx == -1) {
117 		ret ~= str;
118 		return ret;
119 	}
120 	ret ~= str[0 .. idx];
121 	ret ~= repacement;
122 	str = str[idx + find.length .. $];
123 	goto more;
124 }
125 
126 unittest {
127 	assert("foobarfoo".replace("foo", "bar") == "barbarbar");
128 }