split the input into chunks by splitting according to separatorFunc but respecting quotes
(input string, separatorFunc func(r rune) bool)
| 113 | // split the input into chunks by splitting according to separatorFunc but respecting |
| 114 | // quotes |
| 115 | func splitFunc(input string, separatorFunc func(r rune) bool) ([]string, error) { |
| 116 | lastQuote := rune(0) |
| 117 | inQuote := false |
| 118 | |
| 119 | // return true if it's part of a chunk, or false if it's a rune that delimit one, as determined by the separatorFunc. |
| 120 | isChunk := func(r rune) bool { |
| 121 | switch { |
| 122 | case !inQuote && isQuote(r): |
| 123 | lastQuote = r |
| 124 | inQuote = true |
| 125 | return true |
| 126 | case inQuote && r == lastQuote: |
| 127 | lastQuote = rune(0) |
| 128 | inQuote = false |
| 129 | return true |
| 130 | case inQuote: |
| 131 | return true |
| 132 | default: |
| 133 | return !separatorFunc(r) |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | var result []string |
| 138 | var chunk strings.Builder |
| 139 | for _, r := range input { |
| 140 | if isChunk(r) { |
| 141 | chunk.WriteRune(r) |
| 142 | } else { |
| 143 | if chunk.Len() > 0 { |
| 144 | result = append(result, chunk.String()) |
| 145 | chunk.Reset() |
| 146 | } |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | if inQuote { |
| 151 | return nil, fmt.Errorf("unmatched quote") |
| 152 | } |
| 153 | |
| 154 | if chunk.Len() > 0 { |
| 155 | result = append(result, chunk.String()) |
| 156 | } |
| 157 | |
| 158 | return result, nil |
| 159 | } |
| 160 | |
| 161 | func isQuote(r rune) bool { |
| 162 | return r == '"' || r == '\'' |