I have a word HelloWorld that I want to split as Hello & World so how do I do that in Dart?

Currently, I have -

String str = 'HelloWorld';

And I don't know how to go further?

I have tried RegExp like

words = str.split(new RegExp(r"[A-Z]"));

But it is not working. How do I separate Hello & World?


Solution 1: Code Maniac

You can try this

r"(?<=[a-z])(?=[A-Z])"

Explanation

  • (?<=[a-z]) - Positive lookbehind. Matches any lowercase letter.
  • (?=[A-Z]) - Positive lookahead.Matches any uppercase letter.

    void main() {
    
       String str = 'HelloWorld';
       var words = str.split(new RegExp(r"(?<=[a-z])(?=[A-Z])"));
       print(words);
    }
    

Prints -> [Hello, World];


Solution 2: Günter Zöchbauer

titleCase from https://pub.dartlang.org/packages/recase provides that (among many others)

var recase = ReCase(str);
print(recase.titleCase);


Solution 3: lrn

You want to split before capital letters, except the first one. Just splitting at capital letters (well, ASCII letters at least) is easy:

// Single character look-ahead for capital letter.
final beforeCapitalLetter = RegExp(r"(?=[A-Z])");
...
var parts = string.split(beforeCapitalLetter);

The problem here is that it splits before the first letter too, giving you an empty first element in the resulting parts. You could just remove that, if you are certain it's there.

if (parts.isNotEmpty && parts[0].isEmpty) parts = parts.sublist(1);

Or, you can get clever with the RegExp:

// Matches before a capital letter that is not also at beginning of string.
final beforeNonLeadingCapitalLetter = RegExp(r"(?=(?!^)[A-Z])");
List<String> splitPascalCase(String input) =>
    input.split(beforeNonLeadingCapitalLetter);

Example results:

print(splitPascalCase("HelloWorld"));  // [Hello, World]
print(splitPascalCase("One")); // [One]
print(splitPascalCase("none")); // [none]
print(splitPascalCase("BFG9000")); // [B, F, G9000]
print(splitPascalCase("XmlHTTPRequest")); // [Xml, H, T, T, P, Request]

(You might want to consider whether the last thing is what you want).

Another option is to not split, but match the parts you want.

final pascalWords = RegExp(r"(?:[A-Z]+|^)[a-z]*");
List<String> getPascalWords(String input) =>
    pascalWords.allMatches(input).map((m) => m[0]).toList();

This extracts all words starting with one or more leading capital letters (or at the beginning of the string). If your string contains only letters, it should do about the same as the previous function. If it contains other things, then those are ignored.

print(getPascalWords("BFG9000")); // [BFG]
print(getPascalWords("XmlHTTPRequest")); // [Xml, HTTPRequest]

Which one to prefer depends on which strings you expect to get as input, and how you want to handle edge-cases: Adjacent capital letters? All capital letters? Empty string?

If its always the concatenation of one or more two-letter-or-longer words with the first letter capitalized, then it's only easy cases, and either method will work.

Edit: Since this was first posted, Dart RegExps have begun supporting look-behinds. With that, it's possible to use split as well by breaking between a lower-case letter and an upper-case letter, as Serdnad says in a comment:

final _pascalWordsRE = RegExp(r"(?<=[a-z])(?=[A-Z])");
List<String> getPascalWords(String input) => pascalWords.split(_pascalWordsRE);

This splits after a lower-case letter and before an upper case letter.