Skip to content

Instantly share code, notes, and snippets.

@aviddiviner
Created April 30, 2015 21:33
Show Gist options
  • Save aviddiviner/64a16ad3858a594f2a9f to your computer and use it in GitHub Desktop.
Save aviddiviner/64a16ad3858a594f2a9f to your computer and use it in GitHub Desktop.
Slice a string into substrings, keeping the matches
// Splits a string into parts by a given pattern, interleaving the matched
// parts with the unmatched parts.
// For example:
// splitInterleaved(/a/, "aabbac") => []string{"a", "a", "bb", "a", "c"}
// Another way of looking at it is:
// regexp.Split() <zip> regexp.FindAllString() <flatten>
//
func splitInterleaved(re *regexp.Regexp, str string) []string {
splits := re.FindAllStringIndex(str, -1) // Find all the split points
slice := make([]string, len(splits)*2+1) // Allocate enough space
// `pos` tracks where we are in the slice
pos := 0
addToSlice := func(part string) {
slice[pos] = part
pos += 1
}
// `strIdx` tracks where we are in the string (which character)
strIdx := 0
for _, split := range splits {
a, b := split[0], split[1]
if a > strIdx {
addToSlice(str[strIdx:a])
}
addToSlice(str[a:b])
strIdx = b
}
// Pick up the end piece if it's left over
if strIdx < len(str) {
addToSlice(str[strIdx:len(str)])
}
// Re-slice to the portion we used
return slice[:pos]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment