1 #!/usr/bin/env python 2 # Copyright 2014 The Chromium Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 6 import re 7 8 def quote(input_str, specials, escape='\\'): 9 """Returns a quoted version of |str|, where every character in the 10 iterable |specials| (usually a set or a string) and the escape 11 character |escape| is replaced by the original character preceded by 12 the escape character.""" 13 14 assert len(escape) == 1 15 16 # Since escape is used in replacement pattern context, so we need to 17 # ensure that it stays a simple literal and cannot affect the \1 18 # that will follow it. 19 if escape == '\\': 20 escape = '\\\\' 21 if len(specials) > 0: 22 return re.sub(r'(' + r'|'.join(specials)+r'|'+escape + r')', 23 escape + r'\1', input_str) 24 return re.sub(r'(' + escape + r')', escape + r'\1', input_str) 25 26 27 def unquote(input_str, specials, escape='\\'): 28 """Splits the input string |input_str| where special characters in 29 the input |specials| are, if not quoted by |escape|, used as 30 delimiters to split the string. The returned value is a list of 31 strings of alternating non-specials and specials used to break the 32 string. The list will always begin with a possibly empty string of 33 non-specials, but may end with either specials or non-specials.""" 34 35 assert len(escape) == 1 36 37 out = [] 38 cur_out = [] 39 cur_special = False 40 lit_next = False 41 for c in input_str: 42 if cur_special: 43 lit_next = (c == escape) 44 if c not in specials or lit_next: 45 cur_special = False 46 out.append(''.join(cur_out)) 47 if not lit_next: 48 cur_out = [c] 49 else: 50 cur_out = [] 51 else: 52 cur_out.append(c) 53 else: 54 if lit_next: 55 cur_out.append(c) 56 lit_next = False 57 else: 58 lit_next = c == escape 59 if c not in specials: 60 if not lit_next: 61 cur_out.append(c) 62 else: 63 out.append(''.join(cur_out)) 64 cur_out = [c] 65 cur_special = True 66 out.append(''.join(cur_out)) 67 return out 68