-
-
Notifications
You must be signed in to change notification settings - Fork 468
Expand file tree
/
Copy pathStringUtils.java
More file actions
242 lines (214 loc) · 7.47 KB
/
StringUtils.java
File metadata and controls
242 lines (214 loc) · 7.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
package io.sentry.util;
import io.sentry.ILogger;
import io.sentry.SentryLevel;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.Iterator;
import java.util.Locale;
import java.util.regex.Pattern;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ApiStatus.Internal
public final class StringUtils {
private static final Charset UTF_8 = Charset.forName("UTF-8");
public static final String PROPER_NIL_UUID = "00000000-0000-0000-0000-000000000000";
private static final String CORRUPTED_NIL_UUID = "0000-0000";
private static final @NotNull Pattern PATTERN_WORD_SNAKE_CASE = Pattern.compile("[\\W_]+");
private StringUtils() {}
public static @Nullable String getStringAfterDot(final @Nullable String str) {
if (str != null) {
final int lastDotIndex = str.lastIndexOf(".");
if (lastDotIndex >= 0 && str.length() > (lastDotIndex + 1)) {
return str.substring(lastDotIndex + 1);
} else {
return str;
}
}
return null;
}
/**
* Returns a Capitalized String and all remaining chars to lower case. eg seSSioN = Session
*
* @param str the String to capitalize
* @return the capitalized String or itself if empty or null
*/
public static @Nullable String capitalize(final @Nullable String str) {
if (str == null || str.isEmpty()) {
return str;
}
return str.substring(0, 1).toUpperCase(Locale.ROOT) + str.substring(1).toLowerCase(Locale.ROOT);
}
/**
* Converts a String to CamelCase format. E.g. metric_bucket => MetricBucket;
*
* @param str the String to convert
* @return the camel case converted String or itself if empty or null
*/
public static @Nullable String camelCase(final @Nullable String str) {
if (str == null || str.isEmpty()) {
return str;
}
String[] words = PATTERN_WORD_SNAKE_CASE.split(str, -1);
StringBuilder builder = new StringBuilder();
for (String w : words) {
builder.append(capitalize(w));
}
return builder.toString();
}
/**
* Removes character specified by the delimiter parameter from the beginning and the end of the
* string.
*
* @param str the String to remove surrounding string from
* @param delimiter the String that is meant to be removed
* @return a string without delimiter character at the beginning and the end of the string
*/
public static @Nullable String removeSurrounding(
@Nullable final String str, @Nullable final String delimiter) {
if (str != null && delimiter != null && str.startsWith(delimiter) && str.endsWith(delimiter)) {
return str.substring(delimiter.length(), str.length() - delimiter.length());
} else {
return str;
}
}
/**
* Converts the given number of bytes to a human-readable string.
*
* @param bytes the number of bytes
* @return a string representing the human-readable byte count (e.g. 1kB, 20 MB, etc.)
*/
public static @NotNull String byteCountToString(long bytes) {
if (-1000 < bytes && bytes < 1000) {
return bytes + " B";
}
CharacterIterator ci = new StringCharacterIterator("kMGTPE");
while (bytes <= -999_950 || bytes >= 999_950) {
bytes /= 1000;
ci.next();
}
return String.format(Locale.ROOT, "%.1f %cB", bytes / 1000.0, ci.current());
}
/**
* Calculates the SHA-1 String hash.
*
* <p>As of now this is only used to determine the local SDK cache folder name based on the
* project DSN and has no other cryptographic related use.
*
* @param str the String
* @param logger the Logger
* @return The hashed String or null otherwise
*/
public static @Nullable String calculateStringHash(
final @Nullable String str, final @NotNull ILogger logger) {
if (str == null || str.isEmpty()) {
return null;
}
try {
// getInstance() method is called with algorithm SHA-1
final MessageDigest md = MessageDigest.getInstance("SHA-1");
// digest() method is called
// to calculate message digest of the input string
// returned as array of byte
final byte[] messageDigest = md.digest(str.getBytes(UTF_8));
// Convert byte array into signum representation
final BigInteger no = new BigInteger(1, messageDigest);
// Convert message digest into hex value
final StringBuilder stringBuilder = new StringBuilder(no.toString(16));
// return the HashText
return stringBuilder.toString();
}
// For specifying wrong message digest algorithms
catch (NoSuchAlgorithmException e) {
logger.log(SentryLevel.INFO, "SHA-1 isn't available to calculate the hash.", e);
} catch (Throwable e) {
logger.log(SentryLevel.INFO, "string: %s could not calculate its hash", e, str);
}
return null;
}
/**
* Counts the occurrences of a character in a String
*
* @param str the String
* @param character the character to count
* @return The number of occurrences of the character in the String
*/
public static int countOf(@NotNull String str, char character) {
int count = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == character) {
count++;
}
}
return count;
}
/**
* Normalizes UUID string representation to adhere to the actual UUID standard
*
* <p>Because Motorola decided that nil UUIDs should look like this: "0000-0000" ;)
*
* @param uuidString the original UUID string representation
* @return proper UUID string, in case it's a corrupted one
*/
public static String normalizeUUID(final @NotNull String uuidString) {
if (uuidString.equals(CORRUPTED_NIL_UUID)) {
return PROPER_NIL_UUID;
}
return uuidString;
}
/**
* Returns a new String joining together given strings using the given delimiter.
*
* @param delimiter the delimiter that separates elements
* @param elements the elements that should be joined together
* @return a new String with elements joined using delimiter
*/
public static String join(
final @NotNull CharSequence delimiter,
final @NotNull Iterable<? extends CharSequence> elements) {
final @NotNull StringBuilder stringBuilder = new StringBuilder();
final @NotNull Iterator<? extends CharSequence> iterator = elements.iterator();
if (iterator.hasNext()) {
stringBuilder.append(iterator.next());
while (iterator.hasNext()) {
stringBuilder.append(delimiter);
stringBuilder.append(iterator.next());
}
}
return stringBuilder.toString();
}
public static @Nullable String toString(final @Nullable Object object) {
if (object == null) {
return null;
}
return object.toString();
}
public static @NotNull String removePrefix(
final @Nullable String string, final @NotNull String prefix) {
if (string == null) {
return "";
}
final int index = string.indexOf(prefix);
if (index == 0) {
return string.substring(prefix.length());
} else {
return string;
}
}
public static @NotNull String substringBefore(
final @Nullable String string, final @NotNull String separator) {
if (string == null) {
return "";
}
final int index = string.indexOf(separator);
if (index >= 0) {
return string.substring(0, index);
} else {
return string;
}
}
}