1 // SciTE - Scintilla based Text Editor
2 /** @file StringHelpers.h
3  ** Definition of widely useful string functions.
4  **/
5 // Copyright 2010 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
7 
8 #ifndef STRINGHELPERS_H
9 #define STRINGHELPERS_H
10 
11 bool StartsWith(std::wstring_view s, std::wstring_view start);
12 bool StartsWith(std::string_view s, std::string_view start);
13 bool EndsWith(std::wstring_view s, std::wstring_view end);
14 bool Contains(std::string const &s, char ch) noexcept;
15 
16 // Substitute is duplicated instead of templated as it was ambiguous when implemented as a template.
17 int Substitute(std::wstring &s, const std::wstring &sFind, const std::wstring &sReplace);
18 int Substitute(std::string &s, const std::string &sFind, const std::string &sReplace);
19 
20 template <typename T>
Remove(T & s,const T & sFind)21 int Remove(T &s, const T &sFind) {
22 	return Substitute(s, sFind, T());
23 }
24 
25 bool RemoveStringOnce(std::string &s, const char *marker);
26 
27 std::string StdStringFromInteger(int i);
28 std::string StdStringFromSizeT(size_t i);
29 std::string StdStringFromDouble(double d, int precision);
30 
31 int IntegerFromString(const std::string &val, int defaultValue);
32 intptr_t IntPtrFromString(const std::string &val, intptr_t defaultValue);
33 long long LongLongFromString(const std::string &val, long long defaultValue);
34 
35 // Basic case lowering that converts A-Z to a-z.
36 // Does not handle non-ASCII characters.
37 void LowerCaseAZ(std::string &s);
38 
MakeUpperCase(char ch)39 constexpr char MakeUpperCase(char ch) noexcept {
40 	if (ch < 'a' || ch > 'z')
41 		return ch;
42 	else
43 		return ch - 'a' + 'A';
44 }
45 
MakeLowerCase(char c)46 constexpr char MakeLowerCase(char c) noexcept {
47 	if (c >= 'A' && c <= 'Z') {
48 		return c - 'A' + 'a';
49 	} else {
50 		return c;
51 	}
52 }
53 
IsASCII(int ch)54 constexpr bool IsASCII(int ch) noexcept {
55 	return (ch >= 0) && (ch < 0x80);
56 }
57 
IsASpace(int ch)58 constexpr bool IsASpace(int ch) noexcept {
59 	return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
60 }
61 
IsADigit(int ch)62 constexpr bool IsADigit(int ch) noexcept {
63 	return (ch >= '0') && (ch <= '9');
64 }
65 
IsAlphabetic(int ch)66 constexpr bool IsAlphabetic(int ch) noexcept {
67 	return ((ch >= 'A') && (ch <= 'Z')) || ((ch >= 'a') && (ch <= 'z'));
68 }
69 
IsAlphaNumeric(int ch)70 constexpr bool IsAlphaNumeric(int ch) noexcept {
71 	return
72 		((ch >= '0') && (ch <= '9')) ||
73 		((ch >= 'a') && (ch <= 'z')) ||
74 		((ch >= 'A') && (ch <= 'Z'));
75 }
76 
77 intptr_t IntegerFromText(const char *s) noexcept;
78 
79 // StringSplit can be expanded over std::string or GUI::gui_string
80 template <typename T>
StringSplit(const T & text,int separator)81 std::vector<T> StringSplit(const T &text, int separator) {
82 	std::vector<T> vs(text.empty() ? 0 : 1);
83 	for (typename T::const_iterator it=text.begin(); it!=text.end(); ++it) {
84 		if (*it == separator) {
85 			vs.push_back(T());
86 		} else {
87 			vs.back() += *it;
88 		}
89 	}
90 	return vs;
91 }
92 
ListFromString(const GUI::gui_string & args)93 inline std::vector<GUI::gui_string> ListFromString(const GUI::gui_string &args) {
94 	return StringSplit(args, '\n');
95 }
96 
97 
98 // Safer version of string copy functions like strcpy, wcsncpy, etc.
99 // Instantiate over fixed length strings of both char and wchar_t.
100 // May truncate if source doesn't fit into dest with room for NUL.
101 
102 template <typename T, size_t count>
StringCopy(T (& dest)[count],const T * source)103 void StringCopy(T(&dest)[count], const T *source) noexcept {
104 	for (size_t i=0; i<count; i++) {
105 		dest[i] = source[i];
106 		if (!source[i])
107 			break;
108 	}
109 	dest[count-1] = 0;
110 }
111 
112 int CompareNoCase(const char *a, const char *b) noexcept;
113 bool EqualCaseInsensitive(const char *a, const char *b) noexcept;
114 bool EqualCaseInsensitive(std::string_view a, std::string_view b) noexcept;
115 bool isprefix(const char *target, const char *prefix) noexcept;
116 
117 constexpr const char *UTF8BOM = "\xef\xbb\xbf";
118 
119 std::u32string UTF32FromUTF8(std::string_view s);
120 unsigned int UTF32Character(const char *utf8) noexcept;
121 
122 std::string Slash(const std::string &s, bool quoteQuotes);
123 unsigned int UnSlash(char *s) noexcept;
124 std::string UnSlashString(const char *s);
125 std::string UnSlashLowOctalString(const char *s);
126 
127 class ILocalize {
128 public:
129 	virtual GUI::gui_string Text(const char *s, bool retainIfNotFound=true) = 0;
130 };
131 
132 /**
133  * This is a fixed length list of strings suitable for display in combo boxes
134  * as a memory of user entries.
135  */
136 template < int sz >
137 class EntryMemory {
138 	std::string entries[sz];
139 public:
Insert(const std::string & s)140 	void Insert(const std::string &s) {
141 		for (int i = 0; i < sz; i++) {
142 			if (entries[i] == s) {
143 				for (int j = i; j > 0; j--) {
144 					entries[j] = entries[j - 1];
145 				}
146 				entries[0] = s;
147 				return;
148 			}
149 		}
150 		for (int k = sz - 1; k > 0; k--) {
151 			entries[k] = entries[k - 1];
152 		}
153 		entries[0] = s;
154 	}
AppendIfNotPresent(const std::string & s)155 	void AppendIfNotPresent(const std::string &s) {
156 		for (int i = 0; i < sz; i++) {
157 			if (entries[i] == s) {
158 				return;
159 			}
160 			if (0 == entries[i].length()) {
161 				entries[i] = s;
162 				return;
163 			}
164 		}
165 	}
166 	void AppendList(const std::string &s, char sep = '|') {
167 		int start = 0;
168 		int end = 0;
169 		while (s[end] != '\0') {
170 			end = start;
171 			while ((s[end] != sep) && (s[end] != '\0'))
172 				++end;
173 			AppendIfNotPresent(s.substr(start, end-start));
174 			start = end + 1;
175 		}
176 	}
Length()177 	int Length() const noexcept {
178 		int len = 0;
179 		for (int i = 0; i < sz; i++)
180 			if (entries[i].length())
181 				len++;
182 		return len;
183 	}
At(int n)184 	std::string At(int n) const {
185 		return entries[n];
186 	}
AsVector()187 	std::vector<std::string>AsVector() {
188 		std::vector<std::string> ret;
189 		for (int i = 0; i < sz; i++) {
190 			if (entries[i].length())
191 				ret.push_back(entries[i].c_str());
192 		}
193 		return ret;
194 	}
195 };
196 
197 typedef EntryMemory < 10 > ComboMemory;
198 
199 #endif
200