@@ -2311,35 +2311,86 @@ def _test_transcript(self, fname, transcript):
23112311 fname , line_num , command , expected , result )
23122312 self .assertTrue (re .match (expected , result , re .MULTILINE | re .DOTALL ), message )
23132313
2314- def _transform_transcript_expected (self , expected ):
2315- """parse the expected text from the transcript into a valid regex"""
2314+ def _transform_transcript_expected (self , s ):
2315+ """parse the string with slashed regexes into a valid regex"""
23162316 slash = '/'
23172317 backslash = '\\ '
23182318 regex = ''
23192319 start = 0
2320+
23202321 while True :
2321- first_slash_pos = expected . find ( slash , start )
2322+ ( regex , first_slash_pos , start ) = self . _escaped_find ( regex , s , start , False )
23222323 if first_slash_pos == - 1 :
23232324 # no more slashes, add the rest of the string and bail
2324- regex += re .escape (expected [start :])
2325+ regex += re .escape (s [start :])
23252326 break
23262327 else :
2327- # there is a slash, go find the next one
2328- second_slash_pos = expected .find (slash , first_slash_pos + 1 )
2328+ # there is a slash, add everything we have found so far
2329+ # add stuff before the first slash as plain text
2330+ regex += re .escape (s [start :first_slash_pos ])
2331+ start = first_slash_pos + 1
2332+ # and go find the next one
2333+ (regex , second_slash_pos , start ) = self ._escaped_find (regex , s , start , True )
23292334 if second_slash_pos > 0 :
2330- # add everything before the first slash as plain text
2331- regex += re .escape (expected [start :first_slash_pos ])
23322335 # add everything between the slashes (but not the slashes)
23332336 # as a regular expression
2334- regex += expected [ first_slash_pos + 1 :second_slash_pos ]
2337+ regex += s [ start :second_slash_pos ]
23352338 # and change where we start looking for slashed on the
23362339 # turn through the loop
23372340 start = second_slash_pos + 1
23382341 else :
23392342 # no closing slash, treat it all as plain text
2340- regex += re .escape (expected [start :])
2343+ regex += re .escape (s [start :])
23412344 return regex
2345+
2346+ def _escaped_find (self , regex , s , start , in_regex ):
2347+ """
2348+ Find the next slash in {s} after {start} that is not preceded by a backslash.
2349+
2350+ If we find an escaped slash, add everything up to and including it to regex,
2351+ updating {start}. {start} therefore serves two purposes, tells us where to start
2352+ looking for the next thing, and also tells us where in {s} we have already
2353+ added things to {regex}
23422354
2355+ {in_regex} specifies whether we are currently searching in a regex, we behave
2356+ differently if we are or if we aren't.
2357+ """
2358+
2359+ while True :
2360+ pos = s .find ('/' , start )
2361+ if pos == - 1 :
2362+ # no match, return to caller
2363+ break
2364+ elif pos == 0 :
2365+ # slash at the beginning of the string, so it can't be
2366+ # escaped. We found it.
2367+ break
2368+ else :
2369+ # check if the slash is preceeded by a backslash
2370+ if s [pos - 1 :pos ] == '\\ ' :
2371+ # it is.
2372+ if in_regex :
2373+ # add everything up to the backslash as a
2374+ # regular expression
2375+ regex += s [start :pos - 1 ]
2376+ # skip the backslash, and add the slash
2377+ regex += s [pos ]
2378+ else :
2379+ # add everything up to the backslash as escaped
2380+ # plain text
2381+ regex += re .escape (s [start :pos - 1 ])
2382+ # and then add the slash as escaped
2383+ # plain text
2384+ regex += re .escape (s [pos ])
2385+ # update start to show we have handled everything
2386+ # before it
2387+ start = pos + 1
2388+ # and continue to look
2389+ else :
2390+ # slash is not escaped, this is what we are looking for
2391+ break
2392+ return (regex , pos , start )
2393+
23432394 def tearDown (self ):
23442395 if self .cmdapp :
23452396 # Restore stdout
0 commit comments