# Find indices of white space characters in a string

This function returns the indices of all white spaces as an array of Integer. It works fine with a small string:

func whiteSpacesIndices(value : String) -> Array<Int> {
var indices: Array<Int> = []
for (index, char) in value.enumerated() {
if char == " " || char == "\n" || char == "\t" {
indices.append(index)
}
}
return indices
}


However when the string is too long, it could be very slow, because it is looping in every character.

Is there a better way for doing it?

• How long is the string tested? Could you please give the character count and the number of spaces? – ielyamani Jun 7 '19 at 23:58
• With a string that has 8447 characters and 1307 spaces, your code takes 0.5ms on my machine – ielyamani Jun 8 '19 at 18:46
• This returns integral positions of white space, but they're not indices, per say. I.e., they cannot be used to index back into the string – Alexander - Reinstate Monica Jun 21 '19 at 4:50

# General remarks

• value, as a parameter name, isn't very descriptive,
• The code considers that white spaces can only be " " or "\n" or "\t". This a performance optimization and supposes prior knowledge of the contents of the string. More generally you could make the check this way:

if char.isWhitespace {
indices.append(index)
}

• Array<Int> is not the same as [String.Index] of IndexSet. A String can be traversed using String.Index and not and Int.

## Performance

The following codeis twice as fast in my tests, but doesn’t work with emoji :

func whiteSpacesIndices(in str : String) -> Array<Int> {
var indices: Array<Int> = []
let blanks: [UInt32] = [32, 10, 9]  //these values correspond to space, new line, and tabulation respectively.
for (index, scalar) in str.unicodeScalars.enumerated() {
if blanks.contains(scalar.value) {
indices.append(index)
}
}
return indices
}


# Free function or instance method?

The whiteSpacesIndices function seems more like a property on strings. It is appropriate for a String to know about the indices of white spaces (and new lines) within itself:

extension String {
var whiteSpaceIndices: [Int] {
var indices = [Int]()
let blanks: [UInt32] = [32, 10, 9]
for (index, scalar) in self.unicodeScalars.enumerated() {
if blanks.contains(scalar.value) {
indices.append(index)
}
}
return indices
}
}


And could be used like so:

"Hello world!".whiteSpaceIndices    //[5]
"ä ö ü".whiteSpaceIndices           //[1, 3]

• Note that your method returns other results than the original code. For the string "ä ö ü" the original code returns [1, 3] and your code returns [2, 5]. – Martin R Jun 8 '19 at 19:49
• Btw, char.isWhitespace returns true for newline characters, the || char.isNewline is not needed. – Martin R Jun 8 '19 at 19:54
• Still different results for "🇩🇪 👨🏼‍⚖️ x" – Martin R Jun 9 '19 at 4:37
• @MartinR from my limited knowledge, I think if we’d like to take emoji into consideration, we’ll have to revert to the code in question. Do share any trick if there is any. – ielyamani Jun 9 '19 at 4:56
• The character/utf8/unicodeScalars are different and have different offsets. But it was not my intention to say that your code “does not work.” I just wanted to make you aware of the difference. It may not be relevant for OP (who did not provide more information about the text), but should be mentioned. – Martin R Jun 9 '19 at 5:08