• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

esentis / string_extensions / 173

28 Jan 2023 05:55PM UTC coverage: 90.896% (-0.9%) from 91.75%
173

push

travis-ci-com

web-flow
Merge pull request #31 from esentis/develop

Updates to 0.6.8

609 of 670 relevant lines covered (90.9%)

1.5 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.09
/lib/string_extensions.dart
1
import 'dart:convert';
2
import 'dart:math';
3

4
import 'package:convert/convert.dart';
5
import 'package:crypto/crypto.dart' as crypto;
6
import 'package:intl/date_symbol_data_local.dart';
7
import 'package:intl/intl.dart';
8
import 'package:string_extensions/string_helpers.dart';
9

10
extension MiscExtensions on String? {
11
  /// Checks if the [length!] of the `String` is more than the length of [s].
12
  ///
13
  /// If the `String` is null or empty, it returns false.
14
  ///
15
  /// ### Example
16
  ///
17
  /// ```dart
18
  /// String foo = 'Hello';
19
  /// bool isMore = foo > 'Hi'; // returns true.
20
  /// ```
21
  bool operator >(String s) {
1✔
22
    if (this.isBlank) {
1✔
23
      return false;
24
    }
25
    return this!.length > s.length;
3✔
26
  }
27

28
  /// Checks if the [length!] of the `String` is more or equal than the length of [s].
29
  ///
30
  /// If the `String` is null or empty, it returns false.
31
  ///
32
  /// ### Example
33
  ///
34
  /// ```dart
35
  /// String foo = 'Hello';
36
  /// bool isMoreOrEqual = foo >= 'Hi'; // returns true.
37
  /// ```
38
  bool operator >=(String s) {
1✔
39
    if (this.isBlank) {
1✔
40
      return false;
41
    }
42
    return this!.length >= s.length;
3✔
43
  }
44

45
  /// Checks if the [length!] of the `String` is less than the length of [s].
46
  ///
47
  /// If the `String` is null or empty, it returns false.
48
  ///
49
  /// ### Example
50
  ///
51
  /// ```dart
52
  /// String foo = 'Hello';
53
  /// bool isLess = foo < 'Hi'; // returns false.
54
  /// ```
55
  bool operator <(String s) {
1✔
56
    if (this.isBlank) {
1✔
57
      return false;
58
    }
59
    return this!.length < s.length;
3✔
60
  }
61

62
  /// Checks if the [length!] of the `String` is less or equal than the length of [s].
63
  ///
64
  /// If the `String` is null or empty, it returns false.
65
  ///
66
  /// ### Example
67
  ///
68
  /// ```dart
69
  /// String foo = 'Hello';
70
  /// bool isLessOrEqual = foo <= 'Hi'; // returns false.
71
  /// ```
72
  bool operator <=(String s) {
1✔
73
    if (this.isBlank) {
1✔
74
      return false;
75
    }
76
    return this!.length <= s.length;
3✔
77
  }
78

79
  /// Removes a text from the `String`.
80
  String operator -(String? s) {
1✔
81
    if (this.isBlank) {
1✔
82
      return '';
83
    }
84
    if (s.isBlank) {
1✔
85
      return this!;
86
    }
87
    return this!.replaceAll(s!, '');
1✔
88
  }
89

90
  /// Returns the average read time duration of the given `String` in seconds.
91
  ///
92
  /// The default calculation is based on 200 words per minute.
93
  ///
94
  /// You can pass the [wordsPerMinute] parameter for different read speeds.
95
  /// ### Example
96
  /// ```dart
97
  /// String foo =  'Hello dear friend how you doing ?';
98
  /// int readTime = foo.readTime(); // returns 3 seconds.
99
  /// ```
100
  int readTime({int wordsPerMinute = 200}) {
1✔
101
    if (this.isBlank) {
1✔
102
      return 0;
103
    }
104
    var words = this!.trim().split(RegExp(r'(\s+)'));
3✔
105
    var magicalNumber = words.length / wordsPerMinute;
2✔
106
    return (magicalNumber * 100).toInt();
2✔
107
  }
108

109
  /// Capitalizes the `String` in normal form.
110
  /// ### Example
111
  /// ```dart
112
  /// String foo = 'hAckErrR';
113
  /// String cFoo = foo.capitalize; // returns 'Hackerrr'.
114
  /// ```
115
  String? get capitalize {
1✔
116
    if (this.isBlank) {
1✔
117
      return this;
118
    }
119
    return '${this![0].toUpperCase()}${this!.substring(1).toLowerCase()}';
5✔
120
  }
121

122
  /// Returns the word count in the given `String`.
123
  ///
124
  /// The pattern is based on spaces.
125
  /// ### Example
126
  /// ```dart
127
  /// String foo = 'Hello dear friend how you doing ?';
128
  /// int count = foo.countWords; // returns 6 words.
129
  /// ```
130
  int get countWords {
1✔
131
    if (this.isBlank) {
1✔
132
      return 0;
133
    }
134
    var words = this!.trim().split(RegExp(r'(\s+)'));
3✔
135
    // We filter out symbols and numbers from the word count
136
    var filteredWords = words.where((e) => e.onlyLatin!.isNotEmpty);
4✔
137
    return filteredWords.length;
1✔
138
  }
139

140
  /// Removes only the numbers from the `String`.
141
  /// ### Example 1
142
  /// ```dart
143
  /// String foo = 'es4e5523nt1is';
144
  /// String noNumbers = foo.removeNumbers; // returns 'esentis'
145
  /// ```
146
  /// ### Example 2
147
  /// ```dart
148
  /// String foo = '1244e*s*4e*5523n*t*1i*s';
149
  /// String noNumbers = foo.removeNumbers; // returns 'e*s*e*n*t*i*s'
150
  /// ```
151
  String? get removeNumbers {
1✔
152
    if (this.isBlank) {
1✔
153
      return this;
154
    }
155
    var regex = RegExp(r'(\d+)');
1✔
156
    return this!.replaceAll(regex, '');
1✔
157
  }
158

159
  /// Returns only the numbers from the `String`.
160
  /// ### Example
161
  /// ```dart
162
  /// String foo = '4*%^55/es4e5523nt1is';
163
  /// String onyNumbers = foo.onlyNumbers; // returns '455455231'
164
  /// ```
165
  String? get onlyNumbers {
1✔
166
    if (this.isBlank) {
1✔
167
      return this;
168
    }
169
    // ignore: unnecessary_raw_strings
170
    var regex = RegExp(r'([^0-9]+)');
1✔
171
    return this!.replaceAll(regex, '');
1✔
172
  }
173

174
  /// Returns only the Latin characters from the `String`.
175
  /// ### Example
176
  /// ```dart
177
  /// String foo = '4*%^55/es4e5523nt1is';
178
  /// String onlyLatin = foo.onlyLatin; // returns 'esentis'
179
  /// ```
180
  String? get onlyLatin {
1✔
181
    if (this.isBlank) {
1✔
182
      return this;
183
    }
184
    // ignore: unnecessary_raw_strings
185
    var regex = RegExp(r'([^a-zA-Z\s]+)');
1✔
186
    return this!.replaceAll(regex, '');
1✔
187
  }
188

189
  /// Returns only the Greek characters from the `String`.
190
  /// ### Example
191
  /// ```dart
192
  /// String foo = '4*%^55/σοφ4e5523ια';
193
  /// String onlyGreek = foo.onlyGreek; // returns 'σοφια'
194
  /// String foo2 = '4*%^55/σοφ4e5523ια aaggαγάπ112η';
195
  /// String onlyGreek2 = foo2.onlyGreek; // returns 'σοφια αγάπη'
196
  /// ```
197
  String? get onlyGreek {
1✔
198
    if (this.isBlank) {
1✔
199
      return this;
200
    }
201
    // ignore: unnecessary_raw_strings
202
    var regex = RegExp(r'([^α-ωΑ-ΩίϊΐόάέύϋΰήώΊΪΌΆΈΎΫΉΏ\s]+)');
1✔
203
    return this!.replaceAll(regex, '');
1✔
204
  }
205

206
  /// Returns only the Latin OR Greek characters from the `String`.
207
  /// ### Example
208
  /// ```dart
209
  /// String foo = '4*%^55/σοφ4e5523ια';
210
  /// String onlyL1 = foo.onlyLetters; // returns 'σοφια'
211
  /// String foo2 = '4*%^55/es4e5523nt1is';
212
  /// String onlyL2 = foo2.onlyLetters; // returns 'esentis'
213
  /// ```
214
  String? get onlyLetters {
1✔
215
    if (this.isBlank) {
1✔
216
      return this;
217
    }
218
    // ignore: unnecessary_raw_strings
219
    var regex = RegExp(r'([^α-ωΑ-ΩίϊΐόάέύϋΰήώΊΪΌΆΈΎΫΉΏa-zA-Z\s]+)');
1✔
220
    return this!.replaceAll(regex, '');
1✔
221
  }
222

223
  /// Returns all special characters from the `String`.
224
  /// ### Example
225
  /// ```dart
226
  /// String foo = '/!@#\$%^\-&*()+",.?":{}|<>~_-`*%^/ese?:"///ntis/!@#\$%^&*(),.?":{}|<>~_-`';
227
  /// String removed = foo.removeSpecial; // returns 'esentis'
228
  /// ```
229
  String? get removeSpecial {
1✔
230
    if (this.isBlank) {
1✔
231
      return this;
232
    }
233
    // ignore: unnecessary_raw_strings
234
    var regex = RegExp(r'[/!@#$%^\-&*()+",.?":{}|<>~_-`]');
1✔
235
    return this!.replaceAll(regex, '');
1✔
236
  }
237

238
  /// Checks whether the `String` is `null`.
239
  /// ### Example 1
240
  /// ```dart
241
  /// String? foo;
242
  /// bool isNull = foo.isNull; // returns true
243
  /// ```
244
  /// ### Example 2
245
  /// ```dart
246
  /// String foo = 'fff';
247
  /// bool isNull = foo.isNull; // returns false
248
  /// ```
249
  bool get isNull {
1✔
250
    return this == null;
251
  }
252

253
  /// Checks whether the `String` is not `null`.
254
  /// ### Example 1
255
  /// ```dart
256
  /// String? foo;
257
  /// bool isNull = foo.isNotNull; // returns false
258
  /// ```
259
  /// ### Example 2
260
  /// ```dart
261
  /// String foo = 'fff';
262
  /// bool isNull = foo.isNotNull; // returns true
263
  /// ```
264
  bool get isNotNull {
1✔
265
    return isNull == false;
2✔
266
  }
267

268
  /// Checks whether the `String` is a valid IPv4.
269
  /// ### Example 1
270
  /// ```dart
271
  /// String foo = '192.168.1.14';
272
  /// bool isIpv4 = foo.isIpv4; // returns true
273
  /// ```
274
  /// ### Example 2
275
  /// ```dart
276
  /// String foo = '192.168.1.14.150.1225';
277
  /// bool isIpv4 = foo.isIpv4; // returns false
278
  /// ```
279
  bool get isIpv4 {
1✔
280
    if (this.isBlank) {
1✔
281
      return false;
282
    }
283
    var regex = RegExp(
1✔
284
        r'((?:^|\s)([a-z]{3,6}(?=://))?(://)?((?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.(?:25[0-5]|2[0-4]\d|[01]?\d\d?))(?::(\d{2,5}))?(?:\s|$))');
285
    return regex.hasMatch(this!);
1✔
286
  }
287

288
  /// Checks whether the `String` is a valid IPv6.
289
  /// ### Example 1
290
  /// ```dart
291
  /// String foo = '2001:0db8:85a3:0000:0000:8a2e:0370:7334';
292
  /// bool isIpv6 = foo.isIpv6; // returns true
293
  /// ```
294
  /// ### Example 2
295
  /// ```dart
296
  /// String foo = '192.168.1.14.150.1225';
297
  /// bool isIpv6 = foo.isIpv6; // returns false
298
  /// ```
299
  bool get isIpv6 {
1✔
300
    if (this.isBlank) {
1✔
301
      return false;
302
    }
303
    this!.substring(0, 1);
1✔
304
    var regex = RegExp(
1✔
305
        r'(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))');
306
    return regex.hasMatch(this!);
1✔
307
  }
308

309
  /// Checks whether the `String` is a valid URL.
310
  /// ### Example 1
311
  /// ```dart
312
  /// String foo = 'foo.1com';
313
  /// bool isUrl = foo.isUrl; // returns false
314
  /// ```
315
  /// ### Example 2
316
  /// ```dart
317
  /// String foo = 'google.com';
318
  /// bool isUrl = foo.isUrl; // returns true
319
  /// ```
320
  bool get isUrl {
1✔
321
    if (this.isBlank) {
1✔
322
      return false;
323
    }
324
    var regex = RegExp(
1✔
325
        r'[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)');
326
    return regex.hasMatch(this!);
1✔
327
  }
328

329
  /// Checks whether the `String` is a valid Date:
330
  ///
331
  /// ### Valid formats
332
  ///
333
  /// * dd/mm/yyyy
334
  /// * dd-mm-yyyyy
335
  /// * dd.mm.yyyy
336
  /// * yyyy-mm-dd
337
  /// * yyyy-mm-dd hrs
338
  /// * 20120227 13:27:00
339
  /// * 20120227T132700
340
  /// * 20120227
341
  /// * +20120227
342
  /// * 2012-02-27T14Z
343
  /// * 2012-02-27T14+00:00
344
  /// * -123450101 00:00:00 Z": in the year -12345
345
  /// * 2002-02-27T14:00:00-0500": Same as "2002-02-27T19:00:00Z
346
  bool get isDate {
1✔
347
    if (this.isBlank) {
1✔
348
      return false;
349
    }
350
    var regex = RegExp(
1✔
351
        r'^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[13-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$');
352
    if (regex.hasMatch(this!)) {
1✔
353
      return true;
354
    }
355
    try {
356
      DateTime.parse(this!);
1✔
357
      return true;
358
    } on FormatException {
1✔
359
      return false;
360
    }
361
  }
362

363
  /// Checks whether the `String` is a valid mail.
364
  /// ### Example
365
  /// ```dart
366
  /// String foo = 'esentis@esentis.com';
367
  /// bool isMail = foo.isMail; // returns true
368
  /// ```
369
  bool get isMail {
1✔
370
    if (this.isBlank) {
1✔
371
      return false;
372
    }
373
    var regex = RegExp(r"(^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$)");
1✔
374
    return regex.hasMatch(this!);
1✔
375
  }
376

377
  /// Checks whether the `String` is a number.
378
  /// ### Example
379
  /// ```dart
380
  /// String foo = '45';
381
  /// bool isNumber = foo.isNumber; // returns true
382
  /// ```
383
  /// ```dart
384
  /// String foo = '45s';
385
  /// String isNumber = foo.isNumber; // returns false
386
  bool get isNumber {
1✔
387
    if (this.isBlank) {
1✔
388
      return false;
389
    }
390
    return num.tryParse(this!) != null;
1✔
391
  }
392

393
  /// Checks whether the `String` complies to below rules :
394
  ///  * At least 1 uppercase
395
  ///  * At least 1 special character
396
  ///  * At least 1 number
397
  ///  * At least 8 characters in length
398
  /// ### Example
399
  /// ```dart
400
  /// String foo = 'qwerty';
401
  /// bool isStrong = foo.isStrongPassword; // returns false
402
  /// ```
403
  /// ```dart
404
  /// String foo = 'IsTh!$Strong';
405
  /// bool isStrong = foo.isStrongPassword; // returns true
406
  /// ```
407
  bool get isStrongPassword {
1✔
408
    if (this.isBlank) {
1✔
409
      return false;
410
    }
411
    var regex = RegExp(
1✔
412
        r'^(?=.*([A-Z]){1,})(?=.*[!@#$&*]{1,})(?=.*[0-9]{1,})(?=.*[a-z]{1,}).{8,100}$');
413
    return regex.hasMatch(this!);
1✔
414
  }
415

416
  /// Checks whether the `String` is a valid Guid.
417
  ///
418
  /// ### Example
419
  /// ```dart
420
  /// String foo = '6d64-4396-8547-1ec1b86e081e';
421
  /// bool isGuid = foo.isGuid; // returns false
422
  /// ```
423
  /// ```dart
424
  /// String foo = '887b7923-6d64-4396-8547-1ec1b86e081e';
425
  /// bool isGuid = foo.isGuid; // returns true
426
  /// ```
427
  bool get isGuid {
1✔
428
    if (this.isBlank) {
1✔
429
      return false;
430
    }
431
    var regex = RegExp(
1✔
432
        r'^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$');
433
    return regex.hasMatch(this!);
1✔
434
  }
435

436
  /// Checks if the `String` exists in a given `Iterable<String>`
437
  /// ### Example
438
  /// ```dart
439
  /// String foo = '6d64-4396-8547-1ec1b86e081e';
440
  /// var iterable = ['fff','gasd'];
441
  /// bool isIn = foo.isIn(iterable); // returns false
442
  /// ```
443
  bool isIn(Iterable<String?> strings) {
1✔
444
    if (this.isBlank) {
1✔
445
      return false;
446
    }
447
    return strings.contains(this);
1✔
448
  }
449

450
  /// Checks if the `String` has only Latin characters.
451
  /// ### Example
452
  /// ```dart
453
  /// String foo = 'this is a τεστ';
454
  /// bool isLatin = foo.isLatin; // returns false
455
  /// String foo2 = 'this is hello world';
456
  /// bool isLatin2 = foo2.isLatin; // returns true
457
  /// ```
458
  bool get isLatin {
1✔
459
    if (this.isBlank) {
1✔
460
      return false;
461
    }
462
    return RegExp(r'^[a-zA-Z\s]+$').hasMatch(this!);
2✔
463
  }
464

465
  /// Checks if the `String` has only Greek characters.
466
  /// ### Example
467
  /// ```dart
468
  /// String foo = 'this is a τεστ';
469
  /// bool isLatin = foo.isGreek; // returns false
470
  /// String foo2 = 'Τα αγαθά κόποις κτώνται';
471
  /// bool isLatin2 = foo2.isGreek; // returns true
472
  /// ```
473
  bool? get isGreek {
1✔
474
    if (this.isBlank) {
1✔
475
      return false;
476
    }
477

478
    return RegExp(r'^[α-ωΑ-ΩίϊΐόάέύϋΰήώΊΪΌΆΈΎΫΉΏ\s]+$').hasMatch(this!);
2✔
479
  }
480

481
  /// Removes only the letters from the `String`.
482
  /// ### Example 1
483
  /// ```dart
484
  /// String foo = 'es4e5523nt1is';
485
  /// String noLetters = foo.removeLetters; // returns '455231'
486
  /// ```
487
  /// ### Example 2
488
  /// ```dart
489
  /// String foo = '1244e*s*4e*5523n*t*1i*s';
490
  /// String noLetters = foo.removeLetters; // returns '1244**4*5523**1*'
491
  /// ```
492
  String? get removeLetters {
1✔
493
    if (this.isBlank) {
1✔
494
      return this;
495
    }
496
    // ignore: unnecessary_raw_strings
497
    var regex = RegExp(r'([a-zA-Z]+)');
1✔
498
    return this!.replaceAll(regex, '');
1✔
499
  }
500

501
  /// Finds all character occurences and returns count as:
502
  /// ```dart
503
  /// List<Map<dynamic,dynamic>>
504
  /// ```
505
  /// ### Example 1
506
  /// ```dart
507
  /// String foo = 'esentis';
508
  /// List occurences = foo.charOccurences; // returns '[{e:2},{i:1},{n:1},{s:2},]'
509
  /// ```
510
  List<Map<String, int>> get charOccurences {
1✔
511
    if (this.isBlank) {
1✔
512
      return [];
1✔
513
    }
514
    // ignore: omit_local_variable_types
515
    List<Map<String, int>> occurences = [];
1✔
516
    var letters = this!.split('')..sort();
2✔
517
    var checkingLetter = letters[0];
1✔
518
    var count = 0;
519
    for (var i = 0; i < letters.length; i++) {
3✔
520
      if (letters[i] == checkingLetter) {
2✔
521
        count++;
1✔
522
        if (i == letters.length - 1) {
3✔
523
          occurences.add({checkingLetter: count});
×
524
          checkingLetter = letters[i];
×
525
        }
526
      } else {
527
        occurences.add({checkingLetter: count});
2✔
528
        checkingLetter = letters[i];
1✔
529
        count = 1;
530
      }
531
    }
532
    return occurences;
533
  }
534

535
  /// Finds a specific's character occurence in the `String`.
536
  ///
537
  /// ### Example
538
  /// ```dart
539
  /// String foo = 'foo';
540
  /// int occ = foo.charCount('o'); // returns 2
541
  /// ```
542
  int charCount(String char) {
1✔
543
    if (this.isBlank) {
1✔
544
      return 0;
545
    }
546
    return this!.split('').fold<int>(
2✔
547
        0, (previousValue, ch) => previousValue + (ch == char ? 1 : 0));
3✔
548
  }
549

550
  /// Finds the most frequent character in the `String`.
551
  /// ### Example 1
552
  /// ```dart
553
  /// String foo = 'Hello World';
554
  /// String mostFrequent = foo.mostFrequent; // returns 'l'
555
  /// ```
556
  String? get mostFrequent {
1✔
557
    if (this.isBlank) {
1✔
558
      return this;
559
    }
560

561
    var occurences = [];
1✔
562
    var letters = this!.split('')..sort();
2✔
563
    var checkingLetter = letters[0];
1✔
564
    var count = 0;
565
    for (var i = 0; i < letters.length; i++) {
3✔
566
      if (letters[i] == checkingLetter) {
2✔
567
        count++;
1✔
568
        if (i == letters.length - 1) {
3✔
569
          occurences.add({checkingLetter: count});
×
570
          checkingLetter = letters[i];
×
571
        }
572
      } else {
573
        occurences.add({checkingLetter: count});
2✔
574
        checkingLetter = letters[i];
1✔
575
        count = 1;
576
      }
577
    }
578
    var mostFrequent = '';
579
    var occursCount = -1;
1✔
580
    occurences.forEach((element) {
2✔
581
      element.forEach((character, occurs) {
2✔
582
        if (occurs > occursCount) {
1✔
583
          mostFrequent = character;
584
          occursCount = occurs;
585
        }
586
      });
587
    });
588
    return mostFrequent;
589
  }
590

591
  /// Returns the `String` reversed.
592
  /// ### Example
593
  /// ```dart
594
  /// String foo = 'Hello World';
595
  /// String reversed = foo.reverse; // returns 'dlrow olleH'
596
  /// ```
597
  String? get reverse {
1✔
598
    if (this.isBlank) {
1✔
599
      return this;
600
    }
601

602
    var letters = this!.split('').toList().reversed;
3✔
603
    return letters.reduce((current, next) => current + next);
3✔
604
  }
605

606
  /// Returns the first [n] characters of the `String`.
607
  ///
608
  /// n is optional, by default it returns the first character of the `String`.
609
  ///
610
  /// If [n] provided is longer than the `String`'s length, the string will be returned.
611
  ///
612
  /// Faster than using
613
  /// ```dart
614
  /// substring(0,count)
615
  /// ```
616
  /// ### Example 1
617
  /// ```dart
618
  /// String foo = 'hello world';
619
  /// String firstChars = foo.first(); // returns 'h'
620
  /// ```
621
  /// ### Example 2
622
  /// ```dart
623
  /// String foo = 'hello world';
624
  /// bool firstChars = foo.first(3); // returns 'hel'
625
  /// ```
626
  String? first({int n = 1}) {
1✔
627
    if (this.isBlank || this!.length < n || n < 0) {
4✔
628
      return this;
629
    }
630

631
    return this!.substring(0, n);
1✔
632
  }
633

634
  /// Returns the last [n] characters of the `String`.
635
  ///
636
  /// [n] is optional, by default it returns the first character of the `String`.
637
  ///
638
  /// If [n] provided is longer than the `String`'s length, the string will be returned.
639
  ///
640
  /// Faster than using
641
  /// ```dart
642
  /// substring(length-n,length)
643
  /// ```
644
  /// ### Example 1
645
  /// ```dart
646
  /// String foo = 'hello world';
647
  /// String firstChars = foo.last(); // returns 'd'
648
  /// ```
649
  /// ### Example 2
650
  /// ```dart
651
  /// String foo = 'hello world';
652
  /// bool firstChars = foo.last(3); // returns 'rld'
653
  /// ```
654
  String? last({int n = 1}) {
1✔
655
    if (this.isBlank || this!.length < n || n < 0) {
4✔
656
      return this;
657
    }
658

659
    return this!.substring(this!.length - n, this!.length);
4✔
660
  }
661

662
  /// Returns the `String` to slug case.
663
  ///
664
  /// ### Example
665
  /// ```dart
666
  /// String foo = 'sLuG Case';
667
  /// String fooSlug = foo.toSlug; // returns 'sLuG_Case'
668
  /// ```
669
  String? get toSlug {
1✔
670
    if (this.isBlank) {
1✔
671
      return this;
672
    }
673

674
    var words = this!.trim().split(RegExp(r'(\s+)'));
3✔
675
    var slugWord = '';
676

677
    if (this!.length == 1) {
2✔
678
      return this;
679
    }
680
    for (var i = 0; i <= words.length - 1; i++) {
4✔
681
      if (i == words.length - 1) {
3✔
682
        slugWord += words[i];
2✔
683
      } else {
684
        slugWord += words[i] + '_';
3✔
685
      }
686
    }
687
    return slugWord;
688
  }
689

690
  /// Returns the `String` to snake_case.
691
  ///
692
  /// ### Example
693
  /// ```dart
694
  /// String foo = 'SNAKE CASE';
695
  /// String fooSNake = foo.toSnakeCase; // returns 'snake_case'
696
  /// ```
697
  String? get toSnakeCase {
1✔
698
    if (this.isBlank) {
1✔
699
      return this;
700
    }
701

702
    var words = this!.toLowerCase().trim().split(RegExp(r'(\s+)'));
4✔
703
    var snakeWord = '';
704

705
    if (this!.length == 1) {
2✔
706
      return this;
707
    }
708
    for (var i = 0; i <= words.length - 1; i++) {
4✔
709
      if (i == words.length - 1) {
3✔
710
        snakeWord += words[i];
2✔
711
      } else {
712
        snakeWord += words[i] + '_';
3✔
713
      }
714
    }
715
    return snakeWord;
716
  }
717

718
  /// Returns the `String` in camelcase.
719
  /// ### Example
720
  /// ```dart
721
  /// String foo = 'Find max of array';
722
  /// String camelCase = foo.toCamelCase; // returns 'findMaxOfArray'
723
  /// ```
724
  String? get toCamelCase {
1✔
725
    if (this.isBlank) {
1✔
726
      return this;
727
    }
728

729
    var words = this!.trim().split(RegExp(r'(\s+)'));
3✔
730
    var result = words[0].toLowerCase();
2✔
731
    for (var i = 1; i < words.length; i++) {
3✔
732
      result += words[i].substring(0, 1).toUpperCase() +
5✔
733
          words[i].substring(1).toLowerCase();
3✔
734
    }
735
    return result;
736
  }
737

738
  /// Returns the `String` title cased.
739
  ///
740
  /// ```dart
741
  /// String foo = 'Hello dear friend how you doing ?';
742
  /// Sting titleCased = foo.toTitleCase; // returns 'Hello Dear Friend How You Doing'.
743
  /// ```
744
  String? get toTitleCase {
1✔
745
    if (this.isBlank) {
1✔
746
      return this;
747
    }
748

749
    var words = this!.trim().toLowerCase().split(' ');
3✔
750
    for (var i = 0; i < words.length; i++) {
3✔
751
      words[i] = words[i].substring(0, 1).toUpperCase() + words[i].substring(1);
7✔
752
    }
753

754
    return words.join(' ');
1✔
755
  }
756

757
  /// Returns a list of the `String`'s characters.
758
  ///
759
  /// O(n)
760
  ///
761
  /// ### Example
762
  /// ```dart
763
  /// String foo = 'abracadabra';
764
  /// List<String> fooArray = foo.toArray; // returns '[a,b,r,a,c,a,d,a,b,r,a]'
765
  /// ```
766
  List<String> get toArray {
2✔
767
    if (this.isBlank) {
2✔
768
      return [];
1✔
769
    }
770

771
    return this!.split('');
2✔
772
  }
773

774
  /// Converts a `String` to a numeric value if possible.
775
  ///
776
  /// If conversion fails, `null` is returned.
777
  ///
778
  /// ### Example
779
  /// ```dart
780
  /// String foo = '4';
781
  /// int fooInt = foo.toNum(); // returns 4;
782
  /// ```
783
  /// ```dart
784
  /// String foo = '4f';
785
  /// var fooNull = foo.toNum(); // returns null;
786
  /// ```
787
  num? toNum() {
1✔
788
    if (this.isBlank) {
1✔
789
      return null;
790
    }
791

792
    return num.tryParse(this!);
1✔
793
  }
794

795
  /// Converts a `String` to`int` if possible.
796
  ///
797
  /// If conversion fails, `null` is returned.
798
  ///
799
  /// ### Example
800
  /// ```dart
801
  /// String foo = '4';
802
  /// int fooInt = foo.toInt(); // returns 4;
803
  /// ```
804
  /// ```dart
805
  /// String foo = '4f';
806
  /// var fooNull = foo.toInt(); // returns null;
807
  /// ```
808
  /// ```dart
809
  /// String foo = '4.0';
810
  /// var fooNull = foo.toInt(); // returns 4;
811
  /// ```
812
  int? toInt() {
1✔
813
    if (this.isBlank) {
1✔
814
      return null;
815
    }
816

817
    return int.tryParse(this!) ?? double.tryParse(this!)?.floor();
3✔
818
  }
819

820
  /// Converts a `String` to`double` if possible.
821
  ///
822
  /// If conversion fails, `null` is returned.
823
  ///
824
  /// ### Example
825
  /// ```dart
826
  /// String foo = '4';
827
  /// int fooInt = foo.toDouble(); // returns 4.0;
828
  /// ```
829
  /// ```dart
830
  /// String foo = '4f';
831
  /// var fooNull = foo.toDouble(); // returns null;
832
  /// ```
833
  double? toDouble() {
1✔
834
    if (this.isBlank) {
1✔
835
      return null;
836
    }
837

838
    return double.tryParse(this!);
1✔
839
  }
840

841
  /// Properly upper cases Greek letters removing their tones.
842
  ///
843
  /// ### Example
844
  /// ```dart
845
  /// String greek = 'Τι κάνεις πώς τα περνάς φίλτατέ μου';
846
  /// String greekUpper = greek.toGreekUpperCase(); // returns 'ΤΙ ΚΑΝΕΙΣ ΠΩΣ ΤΑ ΠΕΡΝΑΣ ΦΙΛΤΑΤΕ ΜΟΥ'
847
  /// ```
848
  String? toGreekUpperCase() {
1✔
849
    if (this.isBlank) {
1✔
850
      return this;
851
    }
852
    return this!.toUpperCase().replaceAllMapped(RegExp(r'[ΆΈΉΊΎΏΌ]'), (match) {
4✔
853
      switch (match.group(0)) {
1✔
854
        case 'Ά':
1✔
855
          return 'Α';
856
        case 'Έ':
1✔
857
          return 'Ε';
858
        case 'Ή':
1✔
859
          return 'Η';
860
        case 'Ί':
1✔
861
          return 'Ι';
862
        case 'Ύ':
1✔
863
          return 'Υ';
864
        case 'Ώ':
1✔
865
          return 'Ω';
866
        case 'Ο':
×
867
          return 'Ο';
868
        default:
869
          return match.group(0) ?? this!.toUpperCase();
×
870
      }
871
    });
872
  }
873

874
  /// Replaces all greek characters with latin. Comes handy when you want to normalize text for search.
875
  ///
876
  /// ### Example
877
  /// ```dart
878
  /// String foo = 'Αριστοτέλης';
879
  /// String fooReplaced = foo.replaceGreek; // returns 'aristotelis'
880
  /// ```
881
  String? get replaceGreek {
1✔
882
    if (this.isBlank) return this;
1✔
883
    var normalizedWord = '';
884
    for (var i = 0; i < this!.length; i++) {
3✔
885
      var character = this![i];
1✔
886
      if (StringHelpers.greekToLatin.containsKey(character)) {
2✔
887
        normalizedWord += StringHelpers.greekToLatin[character]!;
3✔
888
      } else {
889
        normalizedWord += character;
×
890
      }
891
    }
892
    return normalizedWord;
893
  }
894

895
  /// Adds a [replacement] character at [index] of the `String`.
896
  ///
897
  /// ### Example
898
  /// ```dart
899
  /// String foo = 'hello';
900
  /// String replaced = foo.replaceAtIndex(index:2,replacement:''); // returns 'helo';
901
  /// ```
902
  String? replaceAtIndex({required int index, required String replacement}) {
1✔
903
    if (this.isBlank) {
1✔
904
      return this;
905
    }
906
    if (index > this!.length) {
2✔
907
      return this;
908
    }
909
    if (index < 0) {
1✔
910
      return this;
911
    }
912

913
    return '${this!.substring(0, index)}$replacement${this!.substring(index + 1, this!.length)}';
5✔
914
  }
915

916
  /// Given a pattern returns the starting indices of all occurences of the [pattern] in the `String`.
917
  ///
918
  /// ### Example
919
  /// ```dart
920
  /// String foo = 'abracadabra';
921
  /// String fooOccs = foo.findPatterns(pattern:'abr'); // returns '[0, 7]'
922
  /// ```
923
  List<int> findPattern({required String pattern}) {
1✔
924
    if (this.isBlank) {
1✔
925
      return [];
1✔
926
    }
927

928
    // ignore: omit_local_variable_types
929
    List<int> occurences = [];
1✔
930
    // How many times the pattern can fit the text provided
931
    var fitCount = (this!.length / pattern.length).truncate().toInt();
5✔
932

933
    if (fitCount > this!.length) {
2✔
934
      return [];
×
935
    }
936
    if (fitCount == 1) {
1✔
937
      if (this == pattern) {
×
938
        return [0];
×
939
      }
940
      return [];
×
941
    }
942

943
    for (var i = 0; i <= this!.length; i++) {
3✔
944
      if (i + pattern.length > this!.length) {
4✔
945
        return occurences;
946
      }
947
      if (this!.substring(i, i + pattern.length) == pattern) {
4✔
948
        occurences.add(i);
1✔
949
      }
950
    }
951

952
    return occurences;
953
  }
954

955
  /// Strips all HTML code from `String`.
956
  ///
957
  /// ### Example
958
  /// ```dart
959
  /// String html = '<script>Hacky hacky.</script> <p>Here is some text. <span class="bold">This is bold. </span></p>';
960
  /// String stripped = foo.stripHtml; // returns 'Hacky hacky. Here is some text. This is bold.';
961
  /// ```
962
  String? get stripHtml {
1✔
963
    if (this.isBlank) {
1✔
964
      return this;
965
    }
966

967
    // ignore: unnecessary_raw_strings
968
    var regex = RegExp(r'<[^>]*>');
1✔
969
    return this!.replaceAll(regex, '');
1✔
970
  }
971

972
  /// If the provided `String` is empty do something.
973
  ///
974
  /// ### Example
975
  /// ```dart
976
  /// String foo = '';
977
  /// foo.ifEmpty(()=>print('String is empty'));
978
  /// ```
979
  String? ifEmpty(Function act) {
1✔
980
    if (this == null) {
981
      return null;
982
    }
983

984
    return this!.trim().isEmpty ? act() : this;
3✔
985
  }
986

987
  /// If the provided `String` is `null` do something.
988
  ///
989
  /// ### Example
990
  /// ```dart
991
  /// String foo = ''
992
  /// foo.ifEmpty(()=>print('String is null'));
993
  /// ```
994
  String ifNull(Function act) {
1✔
995
    if (this != null) {
996
      return this!;
997
    }
998

999
    return act();
1✔
1000
  }
1001

1002
  /// Provide default value if the `String` is `null`.
1003
  ///
1004
  /// ### Example
1005
  /// ```dart
1006
  /// String? foo = null;
1007
  /// foo.ifNull('dont be null'); // returns 'dont be null'
1008
  /// ```
1009
  String? defaultValue(String defautlValue) {
1✔
1010
    if (this != null) {
1011
      return this;
1012
    }
1013
    return defautlValue;
1014
  }
1015

1016
  /// Repeats the `String` [count] times.
1017
  ///
1018
  /// ### Example
1019
  /// ```dart
1020
  /// String foo = 'foo';
1021
  /// String fooRepeated = foo.repeat(5); // 'foofoofoofoofoo'
1022
  /// ```
1023
  String? repeat(int count) {
1✔
1024
    if (this.isBlank || count <= 0) {
2✔
1025
      return this;
1026
    }
1027
    var repeated = this!;
1028
    for (var i = 0; i < count - 1; i++) {
3✔
1029
      repeated += this!;
1✔
1030
    }
1031
    return repeated;
1032
  }
1033

1034
  /// Squeezes the `String` by removing repeats of a given character.
1035
  ///
1036
  /// ### Example
1037
  /// ```dart
1038
  /// String foo = 'foofoofoofoofoo';
1039
  /// String fooSqueezed = foo.squeeze('o'); // 'fofofofofo';
1040
  /// ```
1041
  String? squeeze(String char) {
1✔
1042
    if (this.isBlank) {
1✔
1043
      return this;
1044
    }
1045

1046
    var sb = '';
1047
    for (var i = 0; i < this!.length; i++) {
3✔
1048
      if (i == 0 ||
1✔
1049
          this![i - 1] != this![i] ||
4✔
1050
          (this![i - 1] == this![i] && this![i] != char)) {
6✔
1051
        sb += this![i];
2✔
1052
      }
1053
    }
1054
    return sb;
1055
  }
1056

1057
  /// Checks if the `String` is consisted of same characters (ignores cases).
1058
  ///
1059
  /// ### Example
1060
  /// ```dart
1061
  /// String foo1 = 'ttttttt'
1062
  /// bool hasSame1 = foo.hasSameCharacters(); // true;
1063
  /// ```
1064
  /// ```dart
1065
  /// String foo = 'ttttttt12'
1066
  /// bool hasSame2 = foo.hasSameCharacters();  // false;
1067
  /// ```
1068
  bool get hasSameCharacters {
1✔
1069
    if (this.isBlank) {
1✔
1070
      return false;
1071
    }
1072

1073
    if (this!.length > 1) {
2✔
1074
      var b = this![0].toLowerCase();
2✔
1075
      for (var i = 1; i < this!.length; i++) {
3✔
1076
        var c = this![i].toLowerCase();
2✔
1077
        if (c != b) {
1✔
1078
          return false;
1079
        }
1080
      }
1081
    }
1082
    return true;
1083
  }
1084

1085
  /// Shuffles the given `String`'s characters.
1086
  ///
1087
  /// ### Example
1088
  /// ```dart
1089
  /// String foo1 = 'esentis';
1090
  /// String shuffled = foo.shuffle; // 'tsniees'
1091
  /// ```
1092
  String? get shuffle {
×
1093
    if (this.isBlank) {
×
1094
      return this;
1095
    }
1096

1097
    var stringArray = toArray;
×
1098
    stringArray.shuffle();
×
1099
    return stringArray.join();
×
1100
  }
1101

1102
  /// The Levenshtein distance between two words is the minimum number of single-character
1103
  ///
1104
  /// edits (insertions, deletions or substitutions) required to change one word into the other.
1105
  ///
1106
  /// ### Example
1107
  /// ```dart
1108
  /// String foo1 = 'esentis';
1109
  /// int dist = foo.getLevenshtein('esentis2'); // 1
1110
  /// ```
1111
  int? getLevenshtein(String b) {
1✔
1112
    if (this.isBlank) {
1✔
1113
      return null;
1114
    }
1115

1116
    var a = this!.toLowerCase();
1✔
1117
    b = b.toLowerCase();
1✔
1118

1119
    List<int> costs = List<int>.filled(b.length + 1, 0);
3✔
1120

1121
    for (var j = 0; j <= b.length; j++) {
3✔
1122
      costs[j] = j;
1✔
1123
    }
1124

1125
    for (var i = 1; i <= a.length; i++) {
3✔
1126
      int nw = costs[0];
1✔
1127
      costs[0] = i;
1✔
1128

1129
      for (var j = 1; j <= b.length; j++) {
3✔
1130
        int cj = min(1 + min(costs[j], costs[j - 1]),
6✔
1131
            a[i - 1] == b[j - 1] ? nw : nw + 1);
6✔
1132
        nw = costs[j];
1✔
1133
        costs[j] = cj;
1✔
1134
      }
1135
    }
1136

1137
    return costs[b.length];
2✔
1138
  }
1139

1140
  /// Inspired from Vincent van Proosdij.
1141
  ///
1142
  /// Formats the `String` with a specific mask.
1143
  ///
1144
  /// You can assign your own [specialChar], defaults to '#'.
1145
  ///
1146
  /// ### Example
1147
  /// ```dart
1148
  ///var string3 = 'esentisgreece';
1149
  ///var mask3 = 'Hello ####### you are from ######';
1150
  ///var masked3 = string3.formatWithMask(mask3); // returns 'Hello esentis you are from greece'
1151
  /// ```
1152
  String? formatWithMask(String mask, {String specialChar = '#'}) {
1✔
1153
    if (this.isBlank) {
1✔
1154
      return this;
1155
    }
1156

1157
    //var buffer = StringBuffer();
1158
    var maskChars = mask.toArray;
1✔
1159
    var index = 0;
1160
    var out = '';
1161
    for (var m in maskChars) {
2✔
1162
      if (m == specialChar) {
1✔
1163
        if (index < this!.length) {
2✔
1164
          out += this![index];
2✔
1165
          index++;
1✔
1166
        }
1167
      } else {
1168
        out += m;
1✔
1169
      }
1170
    }
1171
    return out;
1172
  }
1173

1174
  /// Removes the first [n] characters from the `String`.
1175
  ///
1176
  /// ### Example
1177
  /// ```dart
1178
  /// String foo = 'esentis'
1179
  /// String newFoo = foo.removeFirst(3) // 'ntis';
1180
  /// ```
1181
  String? removeFirst(int n) {
1✔
1182
    if (this.isBlank) {
1✔
1183
      return this;
1184
    }
1185

1186
    if (n <= 0) {
1✔
1187
      return this;
1188
    }
1189
    if (n >= this!.length) {
2✔
1190
      return '';
1191
    }
1192
    return this!.substring(n, this!.length);
2✔
1193
  }
1194

1195
  /// Removes the last [n] characters from the `String`.
1196
  ///
1197
  /// ### Example
1198
  /// ```dart
1199
  /// String foo = 'esentis';
1200
  /// String newFoo = foo.removeLast(3); // 'esen';
1201
  /// ```
1202
  String? removeLast(int n) {
1✔
1203
    if (this.isBlank || n <= 0) {
2✔
1204
      return this;
1205
    }
1206

1207
    if (n >= this!.length) {
2✔
1208
      return '';
1209
    }
1210
    return this!.substring(0, this!.length - n);
3✔
1211
  }
1212

1213
  /// Trims the `String` to have maximum [n] characters.
1214
  ///
1215
  /// ### Example
1216
  /// ```dart
1217
  /// String foo = 'esentis';
1218
  /// String newFoo = foo.maxChars(3); // 'esen';
1219
  /// ```
1220
  String? maxChars(int n) {
1✔
1221
    if (this.isBlank || n >= this!.length) {
3✔
1222
      return this;
1223
    }
1224

1225
    if (n <= 0) {
1✔
1226
      return '';
1227
    }
1228

1229
    return this!.substring(0, n);
1✔
1230
  }
1231

1232
  /// Reverses slash in the `String`, by providing [direction],
1233
  ///
1234
  /// `0 = / -> \\`
1235
  ///
1236
  /// `1 = \\-> /`
1237
  ///
1238
  /// ### Example
1239
  /// ```dart
1240
  /// String foo1 = 'C:/Documents/user/test';
1241
  /// String revFoo1 = foo1.reverseSlash(0); // returns 'C:\Documents\user\test'
1242
  ///
1243
  /// String foo2 = 'C:\\Documents\\user\\test';
1244
  /// String revFoo2 = foo1.reverseSlash(1); // returns 'C:/Documents/user/test'
1245
  /// ```
1246
  String? reverseSlash(int direction) {
1✔
1247
    if (this.isBlank) {
1✔
1248
      return this;
1249
    }
1250

1251
    switch (direction) {
1252
      case 0:
1✔
1253
        return this!.replaceAll('/', '\\');
1✔
1254
      case 1:
1✔
1255
        return this!.replaceAll('\\', '/');
1✔
1256
      default:
1257
        return this;
1258
    }
1259
  }
1260

1261
  /// Returns the character at [index] of the `String`.
1262
  ///
1263
  /// ### Example
1264
  ///
1265
  /// ```dart
1266
  /// String foo1 = 'esentis';
1267
  /// String char1 = foo1.charAt(0); // returns 'e'
1268
  /// String char2 = foo1.charAt(4); // returns 'n'
1269
  /// String? char3 = foo1.charAt(-20); // returns null
1270
  /// String? char4 = foo1.charAt(20); // returns null
1271
  /// ```
1272
  String? charAt(int index) {
1✔
1273
    if (this.isBlank) {
1✔
1274
      return this;
1275
    }
1276

1277
    if (index > this!.length) {
2✔
1278
      return null;
1279
    }
1280
    if (index < 0) {
1✔
1281
      return null;
1282
    }
1283
    return this!.split('')[index];
2✔
1284
  }
1285

1286
  /// Appends a [suffix] to the `String`.
1287
  ///
1288
  /// ### Example
1289
  ///
1290
  /// ```dart
1291
  /// String foo = 'hello';
1292
  /// String newFoo = foo1.append(' world'); // returns 'hello world'
1293
  /// ```
1294
  String append(String suffix) {
1✔
1295
    if (this.isBlank) {
1✔
1296
      return suffix;
1297
    }
1298

1299
    return this! + suffix;
1✔
1300
  }
1301

1302
  /// Prepends a [prefix] to the `String`.
1303
  ///
1304
  /// ### Example
1305
  ///
1306
  /// ```dart
1307
  /// String foo = 'world';
1308
  /// String newFoo = foo1.prepend('hello '); // returns 'hello world'
1309
  /// ```
1310
  String prepend(String prefix) {
1✔
1311
    if (this.isBlank) {
1✔
1312
      return prefix;
1313
    }
1314

1315
    return prefix + this!;
1✔
1316
  }
1317

1318
  /// Tries to format the current `String` to price amount.
1319
  ///
1320
  /// You can optionally pass the [currencySymbol] to append a symbol to the formatted text.
1321
  ///
1322
  /// ### Example
1323
  ///
1324
  /// ```dart
1325
  /// String price = '1234567';
1326
  /// String formattedPrice = foo1.toPriceAmount(currencySymbol: '€'); // returns '12.345,67 €'
1327
  /// ```
1328
  String? toPriceAmount({String? currencySymbol}) {
1✔
1329
    if (this.isBlank) {
1✔
1330
      return this;
1331
    }
1332

1333
    try {
1334
      var f = NumberFormat.currency(locale: 'el_GR');
1✔
1335

1336
      return f
1337
          .format(double.tryParse(this!.replaceAll(',', '.')))
3✔
1338
          .replaceAll('EUR', '')
1✔
1339
          .trim()
1✔
1340
          .append(currencySymbol == null ? '' : ' $currencySymbol');
2✔
1341
    } catch (e) {
1342
      return null;
1343
    }
1344
  }
1345

1346
  /// Returns the day name of the date provided in `String` format.
1347
  ///
1348
  /// If the date is in `DateTime` format, you can convert it to `String` `DateTime().toString()`.
1349
  ///
1350
  /// You can provide the [locale] to filter the result to a specific language.
1351
  ///
1352
  /// Defaults to 'en-US'.
1353
  ///
1354
  /// ### Example
1355
  ///
1356
  /// ```dart
1357
  /// String date = '2021-10-23';
1358
  /// String day = date.getDayFromDate(); // returns 'Saturday'
1359
  /// String grDay = date.getDayFromDate(locale:'el'); // returns 'Σάββατο'
1360
  /// ```
1361
  String? getDayFromDate({String locale = 'en'}) {
1✔
1362
    initializeDateFormatting(locale);
1✔
1363
    if (this.isBlank) {
1✔
1364
      return this;
1365
    }
1366

1367
    var date = DateTime.tryParse(this!);
1✔
1368
    if (date == null) {
1369
      return null;
1370
    }
1371
    return DateFormat('EEEE', locale).format(date).toString();
3✔
1372
  }
1373

1374
  /// Returns the month name of the date provided in `String` format.
1375
  ///
1376
  /// If the date is in `DateTime` format, you can convert it to `String` `DateTime().toString()`.
1377
  ///
1378
  /// You can provide the [locale] to filter the result to a specific language.
1379
  ///
1380
  /// Defaults to 'en-US'.
1381
  ///
1382
  /// ### Example
1383
  ///
1384
  /// ```dart
1385
  /// String date = '2021-10-23';
1386
  /// String month = date.getMonthFromDate(); // returns 'August'
1387
  /// String grMonth = date.getMonthFromDate(locale:'el'); // returns 'Αυγούστου'
1388
  /// ```
1389
  String? getMonthFromDate({String locale = 'en'}) {
1✔
1390
    initializeDateFormatting(locale);
1✔
1391
    if (this.isBlank) {
1✔
1392
      return this;
1393
    }
1394

1395
    var date = DateTime.tryParse(this!);
1✔
1396
    if (date == null) {
1397
      return null;
1398
    }
1399
    return DateFormat('MMMM', locale).format(date).toString();
3✔
1400
  }
1401

1402
  /// Returns the first day of the month from the provided `DateTime` in `String` format.
1403
  ///
1404
  /// If the date is in `DateTime` format, you can convert it to `String` `DateTime().toString()`.
1405
  ///
1406
  /// You can provide the [locale] to filter the result to a specific language.
1407
  ///
1408
  /// Defaults to 'en-US'.
1409
  ///
1410
  /// ### Example
1411
  ///
1412
  /// ```dart
1413
  /// String date = '2021-10-23';
1414
  /// String day = date.firstDayOfDate(); // returns 'Friday'
1415
  /// String grDay = date.firstDayOfDate(locale:'el'); // returns 'Παρασκευή'
1416
  /// ```
1417
  String? firstDayOfMonth({String locale = 'en'}) {
1✔
1418
    initializeDateFormatting(locale);
1✔
1419
    if (this.isBlank) {
1✔
1420
      return this;
1421
    }
1422

1423
    var date = DateTime.tryParse(this!);
1✔
1424
    if (date == null) {
1425
      return null;
1426
    }
1427
    return DateFormat('EEEE', locale)
1✔
1428
        .format(DateTime(date.year, date.month, 1))
4✔
1429
        .toString();
1✔
1430
  }
1431

1432
  /// Returns the last day of the month from the provided `DateTime` in `String` format.
1433
  ///
1434
  /// If the date is in `DateTime` format, you can convert it to `String` `DateTime().toString()`.
1435
  ///
1436
  /// You can provide the [locale] to filter the result to a specific language.
1437
  ///
1438
  /// Defaults to 'en-US'.
1439
  ///
1440
  /// ### Example
1441
  ///
1442
  /// ```dart
1443
  /// String date = '2021-10-23';
1444
  /// String day = date.firstDayOfDate(); // returns 'Friday'
1445
  /// String grDay = date.firstDayOfDate(locale:'el'); // returns 'Παρασκευή'
1446
  /// ```
1447
  String? lastDayOfMonth({String locale = 'en'}) {
1✔
1448
    initializeDateFormatting(locale);
1✔
1449
    if (this.isBlank) {
1✔
1450
      return this;
1451
    }
1452

1453
    var date = DateTime.tryParse(this!);
1✔
1454
    if (date == null) {
1455
      return null;
1456
    }
1457
    return DateFormat('EEEE', locale)
1✔
1458
        .format(
1✔
1459
          DateTime(date.year, date.month + 1, 1).add(
5✔
1460
            const Duration(days: -1),
1461
          ),
1462
        )
1463
        .toString();
1✔
1464
  }
1465

1466
  /// Returns the left side of the `String` starting from [char].
1467
  ///
1468
  /// If [char] doesn't exist, `null` is returned.
1469
  /// ### Example
1470
  ///
1471
  /// ```dart
1472
  ///  String s = 'peanutbutter';
1473
  ///  String foo = s.leftOf('butter'); // returns 'peanut'
1474
  /// ```
1475
  String? leftOf(String char) {
1✔
1476
    if (this.isBlank) {
1✔
1477
      return this;
1478
    }
1479

1480
    int index = this!.indexOf(char);
1✔
1481
    if (index == -1) {
2✔
1482
      return null;
1483
    }
1484

1485
    return this!.substring(0, index);
1✔
1486
  }
1487

1488
  /// Returns the right side of the `String` starting from [char].
1489
  ///
1490
  /// If [char] doesn't exist, `null` is returned.
1491
  ///
1492
  /// ### Example
1493
  ///
1494
  /// ```dart
1495
  ///  String s = 'peanutbutter';
1496
  ///  String foo = s.rightOf('peanut'); // returns 'butter'
1497
  /// ```
1498
  String? rightOf(String char) {
1✔
1499
    if (this.isBlank) {
1✔
1500
      return this;
1501
    }
1502

1503
    int index = this!.indexOf(char);
1✔
1504

1505
    if (index == -1) {
2✔
1506
      return null;
1507
    }
1508
    return this!.substring(index + char.length, this!.length);
4✔
1509
  }
1510

1511
  /// Truncates the `String` when more than `length` characters exist.
1512
  ///
1513
  /// [length] must be more than 0.
1514
  ///
1515
  /// If [length] > String.length the same `String` is returned without truncation.
1516
  ///
1517
  /// ### Example
1518
  ///
1519
  /// ```dart
1520
  /// String f = 'congratulations';
1521
  /// String truncated = f.truncate(3); // Returns 'con...'
1522
  /// ```
1523
  String? truncate(int length) {
1✔
1524
    if (this.isBlank || length <= 0 || length >= this!.length) {
4✔
1525
      return this;
1526
    }
1527

1528
    return '${this!.substring(0, length)}...';
2✔
1529
  }
1530

1531
  /// Truncates a long `String` in the middle while retaining the beginning and the end.
1532
  ///
1533
  /// [maxChars] must be more than 0.
1534
  ///
1535
  /// If [maxChars] > String.length the same `String` is returned without truncation.
1536
  ///
1537
  /// ### Example
1538
  ///
1539
  /// ```dart
1540
  /// String f = 'congratulations';
1541
  /// String truncated = f.truncateMiddle(5); // Returns 'con...ns'
1542
  /// ```
1543
  String? truncateMiddle(int maxChars) {
1✔
1544
    if (this.isBlank || maxChars <= 0 || maxChars > this!.length) {
4✔
1545
      return this;
1546
    }
1547

1548
    int leftChars = (maxChars / 2).ceil();
2✔
1549
    int rightChars = maxChars - leftChars;
1✔
1550
    return '${this!.first(n: leftChars)}...${this!.last(n: rightChars)}';
3✔
1551
  }
1552

1553
  /// Quotes the `String` adding "" at the start & at the end.
1554
  ///
1555
  /// Removes all " characters from the `String` before adding the quotes.
1556
  ///
1557
  /// ### Example
1558
  ///
1559
  /// ```dart
1560
  /// String text = '"""Is this real"';
1561
  /// String quote = text.quote; // "Is this real"
1562
  /// ```
1563
  String? get quote {
1✔
1564
    if (this.isBlank) {
1✔
1565
      return this;
1566
    }
1567

1568
    String normalizedString = this!.replaceAll('"', '');
1✔
1569

1570
    return normalizedString.append('"').prepend('"');
2✔
1571
  }
1572

1573
  /// Trims leading and trailing spaces from the `String`, so as extra spaces in between words.
1574
  ///
1575
  /// ### Example
1576
  ///
1577
  /// ```dart
1578
  /// String text = '    esentis    thinks   ';
1579
  /// String trimmed = text.trimAll ; // returns 'esentis thinks'
1580
  /// ```
1581
  String? get trimAll {
1✔
1582
    if (this.isBlank) {
1✔
1583
      return this;
1584
    }
1585

1586
    return this!.trim().replaceAll(RegExp(' +'), ' ');
3✔
1587
  }
1588

1589
  /// Checks the `String` and maps the value to a `bool` if possible.
1590
  ///
1591
  /// ### Example
1592
  ///
1593
  /// ```dart
1594
  /// String text = 'yes';
1595
  /// bool? textBool = text.toBool ; // returns true
1596
  /// ```
1597
  bool? get toBool {
1✔
1598
    if (this.isBlank) {
1✔
1599
      return null;
1600
    }
1601

1602
    if (this?.toLowerCase() == 'true' || this?.toLowerCase() == 'yes') {
4✔
1603
      return true;
1604
    }
1605
    if (this?.toLowerCase() == 'false' || this?.toLowerCase() == 'no') {
4✔
1606
      return false;
1607
    }
1608
    return null;
1609
  }
1610

1611
  /// Returns the `String` after a specific character.
1612
  ///
1613
  /// ### Example
1614
  ///
1615
  /// ```dart
1616
  /// String test = 'hello brother what a day today';
1617
  /// String afterString = test.after('brother'); // returns ' what a day today'
1618
  /// ```
1619
  String? after(String pattern) {
1✔
1620
    if (this.isBlank) {
1✔
1621
      return this;
1622
    }
1623

1624
    if (!this!.contains(pattern)) {
1✔
1625
      return '';
1626
    }
1627

1628
    List<String> patternWords = pattern.split(' ');
1✔
1629

1630
    if (patternWords.isEmpty) {
1✔
1631
      return '';
1632
    }
1633
    int indexOfLastPatternWord = this!.indexOf(patternWords.last);
2✔
1634

1635
    if (patternWords.last.length == 0) {
3✔
1636
      return '';
1637
    }
1638

1639
    return this!.substring(
1✔
1640
        indexOfLastPatternWord + patternWords.last.length, this!.length);
4✔
1641
  }
1642

1643
  /// Returns the `String` before a specific character
1644
  ///
1645
  /// ### Example
1646
  ///
1647
  /// ```dart
1648
  /// String test = 'brother what a day today';
1649
  /// String beforeString = test.before('brother'); // returns 'hello '
1650
  /// ```
1651
  String? before(String pattern) {
1✔
1652
    if (this.isBlank) {
1✔
1653
      return this;
1654
    }
1655

1656
    if (!this!.contains(pattern)) {
1✔
1657
      return '';
1658
    }
1659

1660
    List<String> patternWords = pattern.split(' ');
1✔
1661

1662
    if (patternWords.isEmpty) {
1✔
1663
      return '';
1664
    }
1665
    int indexOfFirstPatternWord = this!.indexOf(patternWords.first);
2✔
1666

1667
    if (patternWords.last.length == 0) {
3✔
1668
      return '';
1669
    }
1670

1671
    return this!.substring(
1✔
1672
      0,
1673
      indexOfFirstPatternWord,
1674
    );
1675
  }
1676

1677
  /// The Jaro distance is a measure of edit distance between two strings
1678
  ///
1679
  /// its inverse, called the Jaro similarity, is a measure of two `String`'s similarity:
1680
  ///
1681
  /// the higher the value, the more similar the strings are.
1682
  ///
1683
  /// ### Example
1684
  ///
1685
  /// ```dart
1686
  /// String t1 = 'esentis';
1687
  /// String t2 = 'esen';
1688
  /// print(t1.getJaro(t2)); // prints 0.8571428571428571
1689
  /// ```
1690
  double getJaro(String t) {
1✔
1691
    if (this.isBlank) {
1✔
1692
      return 1;
1693
    }
1694

1695
    final int sLen = this!.length;
1✔
1696
    final int tLen = t.length;
1✔
1697

1698
    if (sLen == 0 && tLen == 0) return 1;
1✔
1699

1700
    final int matchDistance = (max(sLen, tLen) / 2 - 1).toInt();
3✔
1701

1702
    final List<bool> sMatches = List<bool>.filled(sLen, false);
1✔
1703
    final List<bool> tMatches = List<bool>.filled(tLen, false);
1✔
1704

1705
    int matches = 0;
1706
    int transpositions = 0;
1707

1708
    for (int i = 0; i < sLen; i++) {
2✔
1709
      final int start = max(0, i - matchDistance);
2✔
1710
      final int end = min(i + matchDistance + 1, tLen);
3✔
1711

1712
      for (int j = start; j < end; j++) {
2✔
1713
        if (tMatches[j]) continue;
1✔
1714
        if (this!.charAt(i) != t.charAt(j)) continue;
3✔
1715
        sMatches[i] = true;
1✔
1716
        tMatches[j] = true;
1✔
1717
        matches++;
1✔
1718
        break;
1719
      }
1720
    }
1721

1722
    if (matches == 0) return 0;
1✔
1723

1724
    int k = 0;
1725
    for (int i = 0; i < sLen; i++) {
2✔
1726
      if (!sMatches[i]) continue;
1✔
1727
      while (!tMatches[k]) {
1✔
1728
        k++;
×
1729
      }
1730
      if (this!.charAt(i) != t.charAt(k)) transpositions++;
3✔
1731
      k++;
1✔
1732
    }
1733

1734
    return ((matches / sLen) +
2✔
1735
            (matches / tLen) +
2✔
1736
            ((matches - transpositions / 2.0) / matches)) /
4✔
1737
        3.0;
1738
  }
1739

1740
  /// Checks if the `String` is Blank (null, empty or only white spaces).
1741
  bool get isBlank => this?.trim().isEmpty ?? true;
6✔
1742

1743
  /// Checks if the `String` is not blank (null, empty or only white spaces).
1744
  bool get isNotBlank => isBlank == false;
3✔
1745

1746
  /// Return [this] if not blank. Otherwise return [newString].
1747
  String? ifBlank(String? newString) =>
1✔
1748
      asIf((s) => s.isNotBlank, this, newString);
3✔
1749

1750
  /// Compares [this] using [comparison] and returns [trueString] if true, otherwise return [falseString].
1751
  ///
1752
  /// ### Example
1753
  ///
1754
  /// ```dart
1755
  /// String s = 'OK'.asIf((s) => s == "OK", "is OK", "is not OK"); // returns "is OK";
1756
  /// ```
1757
  String? asIf(bool Function(String?) comparison, String? trueString,
1✔
1758
          String? falseString) =>
1759
      comparison(this) ? trueString : falseString;
1✔
1760

1761
  /// Wraps the `String` between two strings. If [before] is a wrap char and [after] is ommited, the method resolve [after] using [getOppositeChar].
1762
  ///
1763
  /// ### Example
1764
  ///
1765
  /// ```dart
1766
  /// String s = "esentis".wrap("AA", after: "BB"); // returns "AAesentisBB";
1767
  /// ```
1768
  String wrap(String? before, {String? after}) {
1✔
1769
    before = before.ifBlank("");
1✔
1770
    if (after.isBlank) {
1✔
1771
      if (before.isCloseWrapChar()) {
1✔
1772
        before = before.getOppositeChar();
×
1773
      }
1774
      after = before.getOppositeChar();
1✔
1775
    }
1776
    return "$before$this${after.ifBlank(before)}";
2✔
1777
  }
1778

1779
  /// Returns the opposite wrap char of the `String` if possible, otherwise returns the same `String`.
1780
  ///
1781
  /// ## Example
1782
  ///
1783
  /// ```dart
1784
  /// String foo = '(';
1785
  /// String oppositeFood = foo.getOppositeChar(); // returns ')';
1786
  /// ```
1787
  String? getOppositeChar() {
1✔
1788
    switch (this) {
1789
      case "(":
1✔
1790
        return ")";
1791
      case ")":
1✔
1792
        return "(";
1793
      case "[":
1✔
1794
        return "]";
1795
      case "]":
1✔
1796
        return "[";
1797
      case "{":
1✔
1798
        return "}";
1799
      case "}":
1✔
1800
        return "{";
1801
      case "<":
1✔
1802
        return ">";
1803
      case ">":
1✔
1804
        return "<";
1805
      case "\\":
1✔
1806
        return "/";
1807
      case "/":
1✔
1808
        return "\\";
1809
      case "¿":
1✔
1810
        return "?";
1811
      case "?":
1✔
1812
        return "¿";
1813
      case "!":
1✔
1814
        return "¡";
1815
      case "¡":
1✔
1816
        return "!";
1817
      default:
1818
        return this;
1819
    }
1820
  }
1821

1822
  /// Check if `String` is a open wrap char: `<`, `{`, `[`, `"`, `'`.
1823
  /// ### Example
1824
  ///
1825
  /// ```dart
1826
  /// bool isOpenWrap = "(".isOpenWrapChar(); // returns true;
1827
  /// ```
1828
  bool isOpenWrapChar() =>
1✔
1829
      this.isNotNull && StringHelpers.openWrappers.contains(this);
3✔
1830

1831
  /// Check if the `String` is a close wrap char: `>`, `}`, `]`, `"`, `'`.
1832
  ///
1833
  /// ### Example
1834
  ///
1835
  /// ```dart
1836
  /// bool isCloseWrap = ")".isCloseWrapChar(); // returns true;
1837
  /// ```
1838
  bool isCloseWrapChar() =>
1✔
1839
      this.isNotNull && StringHelpers.closeWrappers.contains(this);
3✔
1840

1841
  /// Continuously removes from the beginning of the `String` any match in [patterns].
1842
  ///
1843
  /// ### Example
1844
  ///
1845
  /// ```dart
1846
  /// String s = "esentis".removeFirstAny(["s", "ng"]);// returns "esentis";
1847
  /// ```
1848
  String? removeFirstAny(List<String?> patterns) {
1✔
1849
    var from = this;
1850
    if (from.isNotBlank) {
1✔
1851
      for (var pattern in patterns) {
2✔
1852
        if (pattern != null && pattern.isNotEmpty) {
1✔
1853
          while (from!.startsWith(pattern)) {
1✔
1854
            from = from.removeFirst(pattern.length);
2✔
1855
          }
1856
        }
1857
      }
1858
    }
1859
    return from;
1860
  }
1861

1862
  /// Continuously removes from the end of the `String`, any match in [patterns].
1863
  ///
1864
  /// ### Example
1865
  ///
1866
  /// ```dart
1867
  /// String s = "esentisfs12".removeLastAny(["12","s","ng","f",]); // returns "esentis";
1868
  /// ```
1869
  String? removeLastAny(List<String?> patterns) {
1✔
1870
    var from = this;
1871
    if (from.isNotBlank) {
1✔
1872
      for (var pattern in patterns) {
2✔
1873
        if (pattern != null && pattern.isNotEmpty) {
1✔
1874
          while (from!.endsWith(pattern)) {
1✔
1875
            from = from.removeLast(pattern.length);
2✔
1876
          }
1877
        }
1878
      }
1879
    }
1880
    return from;
1881
  }
1882

1883
  /// Continuously removes from the beginning & the end of the `String`, any match in [patterns].
1884
  String? removeFirstAndLastAny(List<String?> patterns) =>
×
1885
      removeFirstAny(patterns).removeLastAny(patterns);
×
1886

1887
  /// Removes the [pattern] from the end of the `String`.
1888
  ///
1889
  /// ### Example
1890
  ///
1891
  /// ```dart
1892
  /// String s = "coolboy".removeLastEqual("y"); // returns "coolbo";
1893
  /// ```
1894
  String? removeLastEqual(String? pattern) => removeLastAny([pattern]);
3✔
1895

1896
  /// Removes any [pattern] match from the beginning of the `String`.
1897
  ///
1898
  /// ### Example
1899
  ///
1900
  /// ```dart
1901
  /// String s = "djing".removeFirstEqual("dj"); // returns "ing"
1902
  /// ```
1903
  String? removeFirstEqual(String? pattern) => removeFirstAny([pattern]);
3✔
1904

1905
  /// Removes any [pattern] match from the beginning & the end of the `String`.
1906
  ///
1907
  /// ### Example
1908
  ///
1909
  /// ```dart
1910
  /// String editted = "abracadabra".removeFirstAndLastEqual("a"); // returns "bracadabr";
1911
  /// ```
1912
  String? removeFirstAndLastEqual(String? pattern) =>
1✔
1913
      removeFirstEqual(pattern).removeLastEqual(pattern);
2✔
1914

1915
  /// Removes everything in the `String` after the first match of the [pattern].
1916
  ///
1917
  /// ### Example
1918
  /// ```dart
1919
  /// String test = 'hello brother what a day today';
1920
  /// String afterString = test.removeAfter('brother'); // returns 'hello ';
1921
  /// ```
1922
  String? removeAfter(String pattern) {
1✔
1923
    if (this.isBlank) {
1✔
1924
      return this;
1925
    }
1926

1927
    if (!this!.contains(pattern)) {
1✔
1928
      return '';
1929
    }
1930

1931
    List<String> patternWords = pattern.split(' ');
1✔
1932

1933
    if (patternWords.isEmpty) {
1✔
1934
      return '';
1935
    }
1936
    int indexOfLastPatternWord = this!.indexOf(patternWords.last);
2✔
1937

1938
    if (patternWords.last.length == 0) {
3✔
1939
      return '';
1940
    }
1941

1942
    return this!.substring(0, indexOfLastPatternWord);
1✔
1943
  }
1944

1945
  /// Removes everything in the `String` before the match of the [pattern].
1946
  ///
1947
  /// ### Example
1948
  ///
1949
  /// ```dart
1950
  /// String test = 'hello brother what a day today';
1951
  /// String afterString = test.removeBefore('brother'); // returns 'brother what a day today';
1952
  /// ```
1953
  String? removeBefore(String pattern) {
1✔
1954
    if (this.isBlank) {
1✔
1955
      return this;
1956
    }
1957

1958
    if (!this!.contains(pattern)) {
1✔
1959
      return '';
1960
    }
1961

1962
    List<String> patternWords = pattern.split(' ');
1✔
1963

1964
    if (patternWords.isEmpty) {
1✔
1965
      return '';
1966
    }
1967
    int indexOfFirstPatternWord = this!.indexOf(patternWords.first);
2✔
1968

1969
    if (patternWords.last.length == 0) {
3✔
1970
      return '';
1971
    }
1972

1973
    return this!.substring(
1✔
1974
      indexOfFirstPatternWord + 1,
1✔
1975
      this!.length,
1✔
1976
    );
1977
  }
1978

1979
  /// Adds a `String` after the first match of the [pattern]. The [pattern] should not be `null`.
1980
  ///
1981
  /// If there is no match, the `String` is returned unchanged.
1982
  ///
1983
  /// ### Example
1984
  ///
1985
  /// ```dart
1986
  /// String test = 'hello brother what a day today';
1987
  /// String afterString = test.addAfter('brother', ' sam '); // returns 'hello brother sam what a day today ';
1988
  /// ```
1989
  String? addAfter(String pattern, String adition) {
1✔
1990
    if (this.isBlank) {
1✔
1991
      return this;
1992
    }
1993

1994
    if (!this!.contains(pattern)) {
1✔
1995
      return this;
1996
    }
1997

1998
    List<String> patternWords = pattern.split(' ');
1✔
1999

2000
    if (patternWords.isEmpty) {
1✔
2001
      return '';
2002
    }
2003
    int indexOfLastPatternWord = this!.indexOf(patternWords.last);
2✔
2004

2005
    if (patternWords.last.length == 0) {
3✔
2006
      return '';
2007
    }
2008

2009
    return this!.substring(0, indexOfLastPatternWord + 1) +
3✔
2010
        adition +
1✔
2011
        this!.substring(indexOfLastPatternWord + 1, this!.length);
3✔
2012
  }
2013

2014
  /// Adds a `String` before the first match of the [pattern]. The [pattern] should not be `null`.
2015
  ///
2016
  /// If there is no match, the `String` is returned unchanged.
2017
  ///
2018
  /// ### Example
2019
  /// ```dart
2020
  /// String test = 'hello brother what a day today';
2021
  /// String afterString = test.addBefore('brother', 'big '); // returns 'hello big brother what a day today';
2022
  /// ```
2023
  String? addBefore(String pattern, String adition) {
1✔
2024
    if (this.isBlank) {
1✔
2025
      return this;
2026
    }
2027

2028
    if (!this!.contains(pattern)) {
1✔
2029
      return this;
2030
    }
2031

2032
    List<String> patternWords = pattern.split(' ');
1✔
2033

2034
    if (patternWords.isEmpty) {
1✔
2035
      return '';
2036
    }
2037
    int indexOfFirstPatternWord = this!.indexOf(patternWords.first);
2✔
2038

2039
    if (patternWords.last.length == 0) {
3✔
2040
      return '';
2041
    }
2042

2043
    return this!.substring(0, indexOfFirstPatternWord) +
2✔
2044
        adition +
1✔
2045
        this!.substring(
1✔
2046
          indexOfFirstPatternWord,
2047
          this!.length,
1✔
2048
        );
2049
  }
2050

2051
  /// Checks if the `String` matches **ANY** of the given [patterns].
2052
  ///
2053
  /// ### Example
2054
  ///
2055
  /// ```dart
2056
  /// bool contains = "abracadabra".containsAny(["a", "p"]); // returns true;
2057
  /// ```
2058
  bool containsAny(List<String?> patterns) {
1✔
2059
    if (this.isNotBlank) {
1✔
2060
      for (String? item in patterns.where((element) => element.isNotBlank)) {
4✔
2061
        if (this!.contains(item!)) {
1✔
2062
          return true;
2063
        }
2064
      }
2065
    }
2066
    return false;
2067
  }
2068

2069
  /// Checks if the `String` matches **ALL** given [patterns].
2070
  ///
2071
  /// ### Example
2072
  ///
2073
  /// ```dart
2074
  /// bool contains = "abracadabra".containsAll(["abra", "cadabra"]; // returns true;
2075
  /// ```
2076
  bool containsAll(List<String?> patterns) {
1✔
2077
    for (String? item in patterns.where((element) => element.isNotBlank)) {
4✔
2078
      if (this.isBlank || this!.contains(item!) == false) {
3✔
2079
        return false;
2080
      }
2081
    }
2082
    return true;
2083
  }
2084

2085
  /// Returns the MD5 hash of the `String`.
2086
  ///
2087
  /// ### Example
2088
  ///
2089
  /// ```dart
2090
  /// String md5 = '123456'.md5; // returns "e10adc3949ba59abbe56e057f20f883e";
2091
  /// ```
2092
  String? get md5 {
1✔
2093
    String? data = this;
2094
    if (data.isNotBlank) {
1✔
2095
      var content = const Utf8Encoder().convert(data!);
1✔
2096
      var md5 = crypto.md5;
2097
      var digest = md5.convert(content);
1✔
2098
      data = hex.encode(digest.bytes);
2✔
2099
    }
2100
    return data;
2101
  }
2102

2103
  /// Formats the `String` to show its proper file size.
2104
  ///
2105
  /// If the `String` is not a valid integer, it is returned unchanged.
2106
  ///
2107
  /// ### Example
2108
  ///
2109
  /// ```dart
2110
  /// String foo = '24117248';
2111
  /// String formatted = foo.formatFileSize; // returns '23 MB';
2112
  /// ```
2113
  String? get formatFileSize {
1✔
2114
    if (this.isBlank) {
1✔
2115
      return this;
2116
    }
2117
    var number = this.toInt();
1✔
2118
    if (number == null) {
2119
      return this;
2120
    }
2121

2122
    List<String> suffix = ["bytes", "KB", "MB", "GB"];
1✔
2123

2124
    int j = 0;
2125

2126
    while (number! >= 1024 && j < 4) {
2✔
2127
      number = (number / 1024).floor();
2✔
2128
      j++;
1✔
2129
    }
2130
    return "$number ${suffix[j]}";
2✔
2131
  }
2132

2133
  /// Transforms the `String` to 1337 alphabet.
2134
  ///
2135
  /// The letters are randomized since each letter can have multiple variations.
2136
  ///
2137
  /// ### Example
2138
  ///
2139
  /// ```dart
2140
  /// String foo = 'esentis';
2141
  /// String leet = foo.toLeet ; // returns '€5£п+!$';
2142
  /// ```
2143
  String? get toLeet {
×
2144
    if (this.isBlank) {
×
2145
      return this;
2146
    }
2147
    final letters = this!.split('');
×
2148

2149
    final leetLetters = [];
×
2150
    letters.forEach((e) {
×
2151
      final count = StringHelpers.leetAlphabet[e].length;
×
2152
      final random = Random().nextInt(count);
×
2153
      print(StringHelpers.leetAlphabet[e][random]);
×
2154
      leetLetters.add(StringHelpers.leetAlphabet[e][random]);
×
2155
    });
2156

2157
    return leetLetters.join();
×
2158
  }
2159

2160
  /// Checks if the `String` provided is a valid credit card number using Luhn Algorithm.
2161
  ///
2162
  /// ### Example
2163
  ///
2164
  /// ```dart
2165
  /// String cc = '5104 4912 8031 9406';
2166
  /// bool isCreditCard = cc.isCreditCard ; returns true;
2167
  /// ```
2168
  bool? get isCreditCard {
1✔
2169
    if (this.isBlank) {
1✔
2170
      return false;
2171
    }
2172

2173
    String trimmed = this!.removeWhiteSpace!;
1✔
2174

2175
    int sum = 0;
2176
    bool alternate = false;
2177
    for (int i = trimmed.length - 1; i >= 0; i--) {
4✔
2178
      List<String> nx = trimmed.toArray;
1✔
2179
      int n = int.parse(nx[i]);
2✔
2180

2181
      if (alternate) {
2182
        n *= 2;
1✔
2183

2184
        if (n > 9) {
1✔
2185
          n = (n % 10) + 1;
2✔
2186
        }
2187
      }
2188
      sum += n;
1✔
2189
      alternate = !alternate;
2190
    }
2191
    return (sum % 10 == 0);
2✔
2192
  }
2193

2194
  /// Removes all whitespace from the `String`.
2195
  ///
2196
  /// ### Example
2197
  ///
2198
  /// ```dart
2199
  /// String foo = '   Hel l o W   orld';
2200
  /// String striped = foo.removeWhiteSpace; // returns 'HelloWorld';
2201
  /// ```
2202
  String? get removeWhiteSpace {
1✔
2203
    if (this.isBlank) {
1✔
2204
      return this;
2205
    }
2206
    return this!.replaceAll(RegExp(r"\s+\b|\b\s"), '');
2✔
2207
  }
2208

2209
  /// Checks whether the `String` is a valid IBAN.
2210
  ///
2211
  /// ### Example
2212
  ///
2213
  /// ```dart
2214
  /// String iban = 'GR1601101250000000012300695';
2215
  /// bool isIban = iban.isIban; // returns true;
2216
  /// ```
2217
  ///
2218
  /// ```dart
2219
  /// String iban = 'GR01250000000012300695';
2220
  /// bool isIban = iban.isIban; // returns false;
2221
  /// ```
2222
  bool get isIban {
1✔
2223
    if (this.isBlank) {
1✔
2224
      return false;
2225
    }
2226

2227
    if (this!.length <= 2) {
2✔
2228
      return false;
2229
    }
2230
    final countryCode = this.first(n: 2);
1✔
2231

2232
    if (!StringHelpers.ibanLen.containsKey(countryCode)) {
2✔
2233
      return false;
2234
    }
2235

2236
    if (StringHelpers.ibanLen[countryCode] != this!.length) {
4✔
2237
      return false;
2238
    }
2239

2240
    var regex = RegExp(
1✔
2241
        r'(^[a-zA-Z]{2}(?:0[2-9]|[1-8][0-9]|9[0-8])[a-zA-Z0-9]{4}[0-9]{6}[a-zA-Z0-9]{0,20}$)');
2242
    return regex.hasMatch(this!);
1✔
2243
  }
2244

2245
  /// Checks whether the provided `String` is a valid Greek ID number.
2246
  ///
2247
  /// The number should be of format XX999999, where XX are letters from both the Greek and the Latin alphabet (ABEZHIKMNOPTYX).
2248
  ///
2249
  /// ### Example
2250
  ///
2251
  /// ```dart
2252
  /// String foo = 'AB123456';
2253
  /// bool isGreekId = foo.isGreekId; // returns true;
2254
  /// ```
2255
  ///
2256
  /// ```dart
2257
  /// String foo = 'AB1234567';
2258
  /// bool isGreekId = foo.isGreekId; // returns false;
2259
  /// ```
2260
  bool get isGreekId {
1✔
2261
    if (this.isBlank) {
1✔
2262
      return false;
2263
    }
2264

2265
    if (this!.length != 8) {
2✔
2266
      return false;
2267
    }
2268

2269
    final List<String> firstTwoLetters = this.first(n: 2)!.split('');
2✔
2270
    final String restLetters = this!.last(n: 6)!;
1✔
2271

2272
    // Besides the first two letters, the rest of the ID should be a 6digit number.
2273
    if (!restLetters.isNumber) {
1✔
2274
      return false;
2275
    }
2276

2277
    // If the first two letters of the provided String are not valid ones.
2278
    if (!StringHelpers.validLetters.contains(firstTwoLetters.first) ||
3✔
2279
        !StringHelpers.validLetters.contains(firstTwoLetters.last)) {
3✔
2280
      return false;
2281
    }
2282

2283
    return true;
2284
  }
2285

2286
  /// Checks whether the `String` is in lowercase.
2287
  bool? get isLowerCase {
1✔
2288
    if (this.isBlank) {
1✔
2289
      return false;
2290
    }
2291
    return this == this!.toLowerCase();
2✔
2292
  }
2293

2294
  /// Checks whether the `String` is in uppercase.
2295
  bool? get isUpperCase {
1✔
2296
    if (this.isBlank) {
1✔
2297
      return false;
2298
    }
2299
    return this == this!.toGreekUpperCase();
2✔
2300
  }
2301

2302
  /// Swaps the case in the `String`.
2303
  ///
2304
  /// ### Example
2305
  ///
2306
  /// ```dart
2307
  /// String foo = 'Hello World';
2308
  /// String swapped = foo.swapCase(); // returns 'hELLO wORLD';
2309
  /// ```
2310
  String? swapCase() {
1✔
2311
    if (this.isBlank) {
1✔
2312
      return this;
2313
    }
2314

2315
    List<String> letters = this!.toArray;
1✔
2316

2317
    String swapped = '';
2318

2319
    for (final l in letters) {
2✔
2320
      if (l.isUpperCase!) {
1✔
2321
        swapped += l.toLowerCase();
2✔
2322
      } else {
2323
        swapped += l.toUpperCase();
2✔
2324
      }
2325
    }
2326
    return swapped;
2327
  }
2328

2329
  /// Checks whether the provided `String` is a valid Swift code.
2330
  bool? get isSwiftCode {
1✔
2331
    var regex = RegExp(r'(^[A-Za-z]{6}[A-Z0-9]{2}([A-Z0-9]{3})?$)');
1✔
2332
    return regex.hasMatch(this!);
1✔
2333
  }
2334

2335
  /// Returns the digit count of the `String`.
2336
  ///
2337
  ///### Example
2338
  ///
2339
  ///```dart
2340
  ///String foo = 'Hello World';
2341
  ///int digitCount = foo.getDigitCount(); // returns 0;
2342
  ///```
2343
  ///
2344
  ///```dart
2345
  ///String foo = 'Hello World 123';
2346
  ///int digitCount = foo.getDigitCount(); // returns 3;
2347
  ///```
2348
  int get digitCount {
1✔
2349
    if (this.isBlank) {
1✔
2350
      return 0;
2351
    }
2352
    RegExp digitsOnly = RegExp(r'\d');
1✔
2353
    return digitsOnly.allMatches(this!).length;
2✔
2354
  }
2355

2356
  /// Checks whether the `String` is a valid ASCII string.
2357
  ///
2358
  /// ### Example
2359
  ///
2360
  /// ```dart
2361
  /// String foo = 'Hello World';
2362
  /// bool isAscii = foo.isAscii; // returns true;
2363
  /// ```
2364
  ///
2365
  /// ```dart
2366
  /// String foo = 'œ∑´®†¥¨ˆøπ';
2367
  /// bool isAscii = foo.isAscii; // returns false;
2368
  /// ```
2369
  bool get isAscii {
1✔
2370
    if (this == null) {
2371
      return false;
2372
    }
2373
    if (this!.isEmpty) {
1✔
2374
      return true;
2375
    }
2376
    final ascii = new RegExp(r'^[\x00-\x7F]+$');
1✔
2377
    return ascii.hasMatch(this!);
1✔
2378
  }
2379

2380
  /// Checks whether the `String` is an anagram of the provided `String`.
2381
  ///
2382
  /// ### Example
2383
  ///
2384
  /// ```dart
2385
  /// String foo = 'Hello World';
2386
  /// bool isAnagram = foo.isAnagram('World Hello'); // returns true;
2387
  /// ```
2388
  ///
2389
  /// ```dart
2390
  /// String foo = 'Hello World';
2391
  /// bool isAnagram = foo.isAnagram('World Hello!'); // returns false;
2392
  /// ```
2393
  bool isAnagramOf(String s) {
1✔
2394
    if (this.isBlank || s.isBlank) {
2✔
2395
      return false;
2396
    }
2397
    final String word1 = this!.removeWhiteSpace!;
1✔
2398

2399
    final String word2 = s.removeWhiteSpace!;
1✔
2400

2401
    if (word1.length != word2.length) {
3✔
2402
      return false;
2403
    }
2404

2405
    Map<String, int> charCount = {};
1✔
2406

2407
    word1
2408
        .split('')
1✔
2409
        .forEach((char) => charCount[char] = (charCount[char] ?? 0) + 1);
5✔
2410

2411
    word2
2412
        .split('')
1✔
2413
        .forEach((char) => charCount[char] = (charCount[char] ?? 0) - 1);
5✔
2414

2415
    return charCount.values.every((count) => count == 0);
4✔
2416
  }
2417

2418
  /// Checks whether the `String` is a palindrome.
2419
  ///
2420
  /// ### Example
2421
  ///
2422
  /// ```dart
2423
  /// String foo = 'Hello World';
2424
  /// bool isPalindrome = foo.isPalindrome; // returns false;
2425
  /// ```
2426
  ///
2427
  /// ```dart
2428
  /// String foo = 'racecar';
2429
  /// bool isPalindrome = foo.isPalindrome; // returns true;
2430
  /// ```
2431
  bool get isPalindrome {
1✔
2432
    if (this.isBlank) {
1✔
2433
      return false;
2434
    }
2435
    return this == this.reverse;
2✔
2436
  }
2437

2438
  /// Checks whether the `String` is consisted of both upper and lower case letters.
2439
  ///
2440
  /// ### Example
2441
  ///
2442
  /// ```dart
2443
  /// String foo = 'Hello World';
2444
  /// bool isMixedCase = foo.isMixedCase; // returns true;
2445
  /// ```
2446
  ///
2447
  /// ```dart
2448
  /// String foo = 'hello world';
2449
  /// bool isMixedCase = foo.isMixedCase; // returns false;
2450
  ///
2451
  bool isMixedCase() {
1✔
2452
    if (this.isBlank) {
1✔
2453
      return false;
2454
    }
2455
    return this!.toUpperCase() != this && this!.toLowerCase() != this;
4✔
2456
  }
2457
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc