Flutter/Dart: Split string by first occurrence

Viewed 51773

Is there a way to split a string by some symbol but only at first occurrence?

Example: date: '2019:04:01' should be split into date and '2019:04:01'
It could also look like this date:'2019:04:01' or this date : '2019:04:01' and should still be split into date and '2019:04:01'

string.split(':');

I tried using the split() method. But it doesn't have a limit attribute or something like that.

8 Answers

You were never going to be able to do all of that, including trimming whitespace, with the split command. You will have to do it yourself. Here's one way:

String s = "date   :   '2019:04:01'";
int idx = s.indexOf(":");
List parts = [s.substring(0,idx).trim(), s.substring(idx+1).trim()];

You can split the string, skip the first item of the list created and re-join them to a string.

In your case it would be something like:

var str = "date: '2019:04:01'";
var parts = str.split(':');
var prefix = parts[0].trim();                 // prefix: "date"
var date = parts.sublist(1).join(':').trim(); // date: "'2019:04:01'"

The trim methods remove any unneccessary whitespaces around the first colon.

Just use the split method on the string. It accepts a delimiter/separator/pattern to split the text by. It returns a list of values separated by the provided delimiter/separator/pattern.

Usage:

const str = 'date: 2019:04:01';
final values = string.split(': '); // Notice the whitespace after colon

Output:

enter image description here

Inspired by python, I've wrote this utility function to support string split with an optionally maximum number of splits. Usage:

split("a=b=c", "="); // ["a", "b", "c"]
split("a=b=c", "=", max: 1); // ["a", "b=c"]
split("",""); // [""] (edge case where separator is empty)
split("a=", "="); // ["a", ""]
split("=", "="); // ["", ""]
split("date: '2019:04:01'", ":", max: 1) // ["date", " '2019:04:01'"] (as asked in question)

Define this function in your code:

List<String> split(String string, String separator, {int max = 0}) {
  var result = List<String>();

  if (separator.isEmpty) {
    result.add(string);
    return result;
  }

  while (true) {
    var index = string.indexOf(separator, 0);
    if (index == -1 || (max > 0 && result.length >= max)) {
      result.add(string);
      break;
    }

    result.add(string.substring(0, index));
    string = string.substring(index + separator.length);
  }

  return result;
}

Online demo: https://dartpad.dev/e9a5a8a5ff803092c76a26d6721bfaf4

I found that very simple by removing the first item and "join" the rest of the List

String date = "date:'2019:04:01'";
List<String> dateParts = date.split(":");
List<String> wantedParts = [dateParts.removeAt(0),dateParts.join(":")];

Use RegExp

string.split(RegExp(r":\s*(?=')"));
  1. Note the use of a raw string (a string prefixed with r)
  2. \s* matches zero or more whitespace character
  3. (?=') matches ' without including itself

You can use extensions and use this one for separating text for the RichText/TextSpan use cases:

extension StringExtension on String {
 List<String> controlledSplit(
  String separator, {
  int max = 1,
  bool includeSeparator = false,
  }) {
   String string = this;
   List<String> result = [];

   if (separator.isEmpty) {
     result.add(string);
     return result;
   }

   while (true) {
     var index = string.indexOf(separator, 0);
     print(index);
     if (index == -1 || (max > 0 && result.length >= max)) {
       result.add(string);
       break;
     }

     result.add(string.substring(0, index));
     if (includeSeparator) {
       result.add(separator);
     }
     string = string.substring(index + separator.length);
   }

   return result;
 }
}

Then you can just reference this as a method for any string through that extension:

void main() {
 String mainString = 'Here was john and john was here';
 print(mainString.controlledSplit('john', max:1, includeSeparator:true));
}

Just convert list to string and search

  productModel.tagsList.toString().contains(filterText.toLowerCase())
Related