200 | | smart_split_re = re.compile('("(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'|[^\\s]+)') |
| 200 | # There are three match blocks (A|B|C). A and B have identical structure, |
| 201 | # differing only by the matched quotation marks. These blocks catch anything |
| 202 | # in quotes as a single match group, optionally surrounded by `_()`. |
| 203 | # C is the uninteresting, trivial case -- it matches any non-empty sequence |
| 204 | # of non-space characters. |
| 205 | # |
| 206 | # Block A should be read as follows, where `` mark string literals and |
| 207 | # NG stands for "non-grouping". |
| 208 | # |
| 209 | # Block B should be read the same way, replacing `'` for `"`. |
| 210 | # |
| 211 | # Reading of block A: |
| 212 | # |
| 213 | # (?:_\()? -- NG optional match ugettext start marker `_(` in the beginning, |
| 214 | # NG needed as `_(` is a digraph |
| 215 | # |
| 216 | # `"` -- match string start marker |
| 217 | # |
| 218 | # (?:[^"\\]|\\.)+ -- NG match for a non-empty sequence of either |
| 219 | # * any character except `"` or `\`, |
| 220 | # * or digraph `\` followed by any single character |
| 221 | # |
| 222 | # `"` -- match string end marker |
| 223 | # |
| 224 | # \)? -- match optional ugettext `)` in the end |
| 225 | # |
| 226 | # Note that this lets throug both `" ")` and `\(" "`, avoiding these |
| 227 | # would make the regex needlessly complex. |
| 228 | smart_split_re = re.compile( |
| 229 | r'((?:_\()?"(?:[^"\\]|\\.)+"\)?' # block A, for "foo bar" |
| 230 | r"|(?:_\()?'(?:[^'\\]|\\.)+'\)?" # block B, for 'foo bar' |
| 231 | r"|[^\s]+)" # block C, anything other without whitespace |
| 232 | ) |
218 | | if bit[0] == '"' and bit[-1] == '"': |
219 | | yield '"' + bit[1:-1].replace('\\"', '"').replace('\\\\', '\\') + '"' |
220 | | elif bit[0] == "'" and bit[-1] == "'": |
221 | | yield "'" + bit[1:-1].replace("\\'", "'").replace("\\\\", "\\") + "'" |
| 254 | prefix, suffix = '', '' |
| 255 | start, end = 1, -1 |
| 256 | if bit[0:2] == '_(' and bit[-1] == ')': |
| 257 | prefix, suffix = '_(', ')' |
| 258 | start, end = 3, -2 |
| 259 | if (bit[0] == '"' and bit[-1] == '"' |
| 260 | or bit[0:3] == '_("' and bit[-2:] == '")'): |
| 261 | yield '%s"%s"%s' % (prefix, |
| 262 | bit[start:end].replace(r'\"', '"').replace(r'\\', '\\'), |
| 263 | suffix) |
| 264 | elif (bit[0] == "'" and bit[-1] == "'" |
| 265 | or bit[0:3] == "_('" and bit[-2:] == "')"): |
| 266 | yield "%s'%s'%s" % (prefix, |
| 267 | bit[start:end].replace(r"\'", "'").replace(r'\\', '\\'), |
| 268 | suffix) |