Changeset 2662


Ignore:
Timestamp:
11/20/11 23:14:43 (2 years ago)
Author:
jdsiiro
Message:

Rewrite of quote_split() to handle several edge cases that the
original version did not handle correctly. Cases also added to the unit
tests...

Location:
pyutilib.misc/trunk/pyutilib/misc
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • pyutilib.misc/trunk/pyutilib/misc/misc.py

    r2595 r2662  
    122122 
    123123 
    124 def quote_split(re_str, str): 
    125     """ 
    126     Split a string, but do not split the string between quotes. 
    127     """ 
    128     mylist = [] 
    129     chars = [] 
    130     state = 1 
    131     quote = [] 
    132     for token in re.split(re_str,str): 
    133         prev = " " 
    134         for character in token: 
    135             if character is "'" or (character == "\"" and prev != "\\"): 
    136                 if state == 1: 
    137                     chars.append(character) 
    138                     quote.append(character) 
    139                     state = 2 
    140                 elif character is quote[-1]: 
    141                     state = 1 
    142                     chars.append(character) 
    143                     quote.pop() 
    144             else: 
    145                 chars.append(character) 
    146                 prev = character 
    147         if state == 1: 
    148             if len(chars) > 0: 
    149                 mylist = mylist + [ string.join(chars,"") ] 
    150                 chars = [] 
     124whitespace_re = re.compile('\s+') 
     125def quote_split(regex_str, src=None): 
     126    """ 
     127    Split a string, but do not split the string between quotes.  If only 
     128    one argument is provided (the string to be split), regex_str 
     129    defaults to '\s+'.  In addition, regex_str can be either a regular 
     130    expression string, or a compiled expression. 
     131    """ 
     132 
     133    if src is None: 
     134        src = regex_str 
     135        regex = whitespace_re 
     136    elif 'match' in dir(regex_str): 
     137        regex = regex_str 
     138    else: 
     139        regex = re.compile(regex_str) 
     140 
     141    # We need to figure out where the quoted strings are.  Given that 
     142    # lots of things may be escaped (e.g., '\\\"'), we can only find the 
     143    # "real" quotes by walking the entire string. <sigh>. 
     144    tokens = [] 
     145    start = 0 
     146    inQuote = '' 
     147    escaping = False 
     148    for idx, char in enumerate(src): 
     149        if escaping: 
     150            escaping = False 
     151        elif char == inQuote: 
     152            inQuote = '' 
    151153        else: 
    152             chars = chars + [ " " ] 
    153     if state == 2: 
     154            if not inQuote and start <= idx: 
     155                g = regex.match(src[idx:]) 
     156                if g: 
     157                    tokens.append(src[start:idx]) 
     158                    start = idx + len(g.group()) 
     159                    # NB: we still want to parse the remainder of the patern 
     160                    # for things like escape characters so that we correctly 
     161                    # parse the entire source string; hence, no 'elif' 
     162            if char == '\\': 
     163                escaping = True 
     164            elif not inQuote and ( char == '"' or char == "'" ): 
     165                inQuote = char 
     166 
     167    if inQuote: 
    154168        raise ValueError, "ERROR: unterminated quotation found in quote_split()" 
    155     return mylist 
    156  
     169 
     170    tokens.append(src[start:]) 
     171    return tokens 
     172         
    157173 
    158174def traceit(frame, event, arg):    #pragma:nocover 
  • pyutilib.misc/trunk/pyutilib/misc/tests/test_misc.py

    r2595 r2662  
    127127            pass 
    128128 
     129        ans=pyutilib.misc.quote_split("a bb\\\" ccc") 
     130        self.assertEqual(ans,["a","bb\\\"","ccc"]) 
     131        self.assertRaises(ValueError, pyutilib.misc.quote_split, 
     132                          ("a bb\\\\\" ccc")) 
     133        ans=pyutilib.misc.quote_split("a \"bb  ccc\"") 
     134        self.assertEqual(ans,["a","\"bb  ccc\""]) 
     135        ans=pyutilib.misc.quote_split("a 'bb \" ccc'") 
     136        self.assertEqual(ans,["a","'bb \" ccc'"]) 
     137        ans=pyutilib.misc.quote_split("a \"bb ' ccc\"") 
     138        self.assertEqual(ans,["a","\"bb ' ccc\""]) 
     139        ans=pyutilib.misc.quote_split("a \"bb \\\\\\\" ccc\"") 
     140        self.assertEqual(ans,["a","\"bb \\\\\\\" ccc\""]) 
     141        ans=pyutilib.misc.quote_split('b',"abbbccc") 
     142        self.assertEqual(ans,["a",'','','ccc']) 
     143        ans=pyutilib.misc.quote_split('b+',"abbbccc") 
     144        self.assertEqual(ans,["a",'ccc']) 
     145        ans=pyutilib.misc.quote_split(' ',"a b\ c") 
     146        self.assertEqual(ans,["a",'b\ c']) 
     147 
     148 
    129149    def test_tuplize(self): 
    130150        ans=pyutilib.misc.tuplize([0,1,2,3,4,5],2,"a") 
Note: See TracChangeset for help on using the changeset viewer.