Course: JavaScript

Progress (0%)

  1. Foundation

  2. Numbers

  3. Strings

  4. Conditions

  5. Loops

  6. Arrays

  7. Functions

  8. Objects

  9. Exceptions

  10. HTML DOM

  11. CSSOM

  12. Events

  13. Drag and Drop

  14. opt Touch Events

  15. Misc

  16. Project: Analog Clock

Exercise: String Split

Exercise 21 Easy

Prerequisites for the exercise

  1. JavaScript Strings — Unicode
  2. JavaScript Strings — Basics
  3. All previous chapters

Objective

Create two variants of a function to split a given string at a given delimiter.

Description

Splitting a string into an array of substrings is an extremely common task while working with them.

The split() string method is used in this regard. It accepts a delimiter string which specifies exactly where we wish to split the main string at.

For instance, given the string 'a|b|c', if we split it with '|' as delimiter, we'd get the array ['a', 'b', 'c']. See how the delimiter itself is chopped off from the main string with the remaining substring bits held on in an array.

As another example, if given the string 'a, b, c,d', and the delimiter ', ' (with the space character included), then splitting the string at this delimiter would yield the array ['a', 'b', 'c,d'] (comprised of 3 elements).

Simple?

In this exercise, you have to define two variants of a function stringSplit() that splits a string into an array of substrings, at a given delimiter.

These variants are detailed as follows.

Variant 1

In the first variant, it must be assumed that the delimiter is not more than 1 character in length.

Shown below are a couple of examples of this function:

stringSplit('a|b|c', '|')
['a', 'b', 'c']
stringSplit('a b c', ' ')
['a', 'b', 'c']
stringSplit('a, b, c', '')
['a', ',', ' ', 'b', ',', ' ', 'c']

Note that if the given delimiter is an empty string, the function must return back an array of all the characters, as in the last statement above.

Variant 2

In the second variant, the delimiter string could be of any arbitrary length.

This is a more general implementation of a string splitting algorithm than the one above where we assumed that the delimiter is either '' or comprised of just one character.

Shown below are a couple of examples:

stringSplit('a||b||c', '||')
['a', 'b', 'c']
stringSplit('a : b : c', ' : ')
['a', 'b', 'c']
stringSplit('aZZZbZZZc', 'ZZZ')
['a', 'b', 'c']
stringSplit('aZZZbZZZc', 'ZZ')
['a', 'Zb', 'Zc']
stringSplit('a, b, c', '')
['a', ',', ' ', 'b', ',', ' ', 'c']

Note that, as with the first variant, if the given delimiter is an empty string, the function must return back an array of all the characters.

View Solution

New file

Inside the directory you created for this course on JavaScript, create a new folder called Exercise-21-String-Split and put the .html solution files for this exercise within it.

Solution

Before we delve into dealing with a given variant of stringSplit(), let's first set up the basic wireframe of the function, i.e. its parameters, its return value, and so on.

Here's the definition:

function stringSplit(str, delimiter) {
   // Code to go here.
}

Both the variants have the same signature, hence we could keep using this same definition for both of them.

In addition to this, there is a common case between them, which we could also solve right now, as we set up the basic structure of the function before focusing on one particular variant.

That common case is when the delimiter is an empty string, whereby we ought to return back an array of the characters of the string.

This case is addressed below:

function stringSplit(str, delimiter) {
   var substrings = [];

   if (delimiter === '') {
      for (var i = 0, len = str.length; i < len; i++) {
         substrings.push(str[i]);
      }
      return substrings;
   }
}

First we check if delimiter is empty and if it is, we iterate over the string str and push each character to the array substrings.

Variant 1

In variant 1 of stringSplit(), we need to assume that delimiter is comprised of just one character (we've already addressed the empty delimiter case above, so that doesn't concern us now).

This largely simplifies the string splitting algorithm.

Anyways, the way we need to approach this problem is as follows: iterate over each character of str, looking for delimiter. When delimiter is found, slice the substring before it starting at a given position and stash it into the substrings array.

Obviously, we've left some details in this description, but you hopefully get the idea.

The most important thing here is to use an index-tracking variable that helps us determine the position from where we have to slice a substring, in the occasion when delimiter is found. Let's call this variable index.

This can be best understood with the help of an example.

Let's suppose that the string str is 'js:cpp:py' and delimiter is ':'. Initially, index = 0.

The figure below shows the first occasion when the delimiter : is found in the string str:

Demonstration of string splitting algorithm

At this stage, a substring is extracted from str from index 0 (inclusive) to the index where delimiter is found, i.e. 2 (exclusive). This substring is 'js'.

Now, since at a subsequent match of delimiter, we need to slice str starting at the index right after the one where its last match was found, we need to update the index-tracking variable to 3. (We don't update it to 2 since the delimiter itself doesn't have to be included in the substring extracted.)

The figure below shows the second occasion when the delimiter : is found in str:

Demonstration of string splitting algorithm

At this stage, a substring is extracted from str starting at index 3, i.e. the current value of index, and ending at index 6 (exclusive). This substring is 'cpp'.

The index-tracking variable index is updated to 7.

After this point, the search for delimiter continues uptil the end of str, but no match is found. In the end, a final substring is extracted starting at index 7 and going all the way to the end of the string.

Demonstration of string splitting algorithm

This yields the substring 'py'.

And this completes our splitting, yielding the three substrings 'js', 'cpp' and 'py'.

Alright, so now is the time to implement this variant of stringSplit() in code.

Here's the complete code:

function stringSplit(str, delimiter) {
   var substrings = [];
   var len = str.length;

   if (delimiter === '') {
      for (var i = 0; i < len; i++) {
         substrings.push(str[i]);
      }
      return substrings;
   }

   var index = 0; // The index-tracking variable.
   for (var i = 0; i < len; i++) {
      if (str[i] === delimiter) {
         substrings.push(str.slice(index, i));
         index = i + 1;
      }
   }
   substrings.push(str.slice(index));

   return substrings;
}

Note that we have taken the declaration of the variable len out of the body of the first if statement. This is because len is needed in the second for loop as well, and so declaring it at the start of the function makes the code more readable and intuitive.

Perfect.

Let's move over to implementing variant 2.

Variant 2

Implementing the second variant of stringSplit() is a little bit intimidating.

It requires us to add a second variable into our algorithm which holds the length of the delimiter string. This variable will be used in the splitting algorithm to determine where to start searching for delimiter up next when one match is found. Let's call it delimiterLength.

Now since delimiter is not just a one-character string, we ought to search for it in str. This can very easily be done using the indexOf() method.

We could use a while loop that goes over str until indexOf() yields -1 indicating that there are no further matches of delimiter in str.

The second parameter of indexOf() would come in handy here. We'd pass it the value of the index-tracking variable so as to search beyond the position where the last match of delimiter was found.

In the end, when the while loop completes, we'd extract a final substring from str, just as we did in the stringSplit() variant above.

Let's consider a sequence of illustrations to understand this better, as we saw above.

Suppose that str is 'java:::ruby:::perl' and delimiter is ':::'. Initially, index = 0 (the index-tracking variable).

The figure below shows the first occasion when the delimiter ::: is found in str:

Demonstration of string splitting algorithm

At this stage, a substring is extracted from str starting at index 0, i.e. the current value of index, and ending at index 4 (exclusive), i.e. where the delimiter is found. This substring is 'java'.

The index-tracking variable index is updated to 7, which is obtained by adding 3, i.e. the value of delimiterLength, to 4.

The figure below shows the second occasion when the delimiter's match is found in str:

Demonstration of string splitting algorithm

A substring is extracted from str starting at index 7, i.e. the current value of index, and ending at index 11 (exclusive). This substring is 'ruby'.

The variable index is updated to 14, which is obtained by adding 3, i.e. the value of delimiterLength, to 11.

Beyond this point, no match of delimiter is found in str. Hence, our iteration ends, and as stated above, as the final step, we extract a substring from str starting at index and going all the way to the end of the string.

The figure below illustrates this:

Demonstration of string splitting algorithm

As underlined in the figure, the substring extracted is 'perl'.

And this completes our splitting, yielding the three substrings 'java', 'ruby' and 'perl'.

Simple?

It's time to implement this variant. Here's the code:

function stringSplit(str, delimiter) {
   var substrings = [];
   var len = str.length;

   if (delimiter === '') {
      for (var i = 0; i < len; i++) {
         substrings.push(str[i]);
      }
      return substrings;
   }

   var index = 0; // The index-tracking variable.
   var indexOfValue; // The value returned by indexOf().
   var delimiterLength = delimiter.length;

   while ((indexOfValue = str.indexOf(delimiter, index)) !== -1) {
      substrings.push(str.slice(index, indexOfValue));
      index = indexOfValue + delimiterLength;
   }
   substrings.push(str.slice(index));

   return substrings;
}

The while loop continues executing as long as str.indexOf(delimiter, index) doesn't return -1, which means that there is no further match of delimiter in str.

In each iteration, a substring is extracted from str starting at the index index (inclusive) and ending at indexOfValue (exclusive), i.e. the index where the match of delimiter is found.

Afterwards, index is updated to the position right after the currently-matched delimiter in str, which employs the delimiterLength variable.

Once the loop exits, a final substring extraction is made, starting from the index index upto the end of str. In the end, the array of substrings substrings is returned.

And with this, we complete this exercise.