Collapses strings and chars on a line to simple "" or '' blocks. We nix strings first so we're not fooled by text like '"http://"' Args: elided: The line being processed. Returns: The line with collapsed strings.
(elided)
| 2126 | |
| 2127 | @staticmethod |
| 2128 | def _CollapseStrings(elided): |
| 2129 | """Collapses strings and chars on a line to simple "" or '' blocks. |
| 2130 | |
| 2131 | We nix strings first so we're not fooled by text like '"http://"' |
| 2132 | |
| 2133 | Args: |
| 2134 | elided: The line being processed. |
| 2135 | |
| 2136 | Returns: |
| 2137 | The line with collapsed strings. |
| 2138 | """ |
| 2139 | if _RE_PATTERN_INCLUDE.match(elided): |
| 2140 | return elided |
| 2141 | |
| 2142 | # Remove escaped characters first to make quote/single quote collapsing |
| 2143 | # basic. Things that look like escaped characters shouldn't occur |
| 2144 | # outside of strings and chars. |
| 2145 | elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub("", elided) |
| 2146 | |
| 2147 | # Replace quoted strings and digit separators. Both single quotes |
| 2148 | # and double quotes are processed in the same loop, otherwise |
| 2149 | # nested quotes wouldn't work. |
| 2150 | collapsed = "" |
| 2151 | while True: |
| 2152 | # Find the first quote character |
| 2153 | match = re.match(r'^([^\'"]*)([\'"])(.*)$', elided) |
| 2154 | if not match: |
| 2155 | collapsed += elided |
| 2156 | break |
| 2157 | head, quote, tail = match.groups() |
| 2158 | |
| 2159 | if quote == '"': |
| 2160 | # Collapse double quoted strings |
| 2161 | second_quote = tail.find('"') |
| 2162 | if second_quote >= 0: |
| 2163 | collapsed += head + '""' |
| 2164 | elided = tail[second_quote + 1 :] |
| 2165 | else: |
| 2166 | # Unmatched double quote, don't bother processing the rest |
| 2167 | # of the line since this is probably a multiline string. |
| 2168 | collapsed += elided |
| 2169 | break |
| 2170 | else: |
| 2171 | # Found single quote, check nearby text to eliminate digit separators. |
| 2172 | # |
| 2173 | # There is no special handling for floating point here, because |
| 2174 | # the integer/fractional/exponent parts would all be parsed |
| 2175 | # correctly as long as there are digits on both sides of the |
| 2176 | # separator. So we are fine as long as we don't see something |
| 2177 | # like "0.'3" (gcc 4.9.0 will not allow this literal). |
| 2178 | if re.search(r"\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$", head): |
| 2179 | match_literal = re.match(r"^((?:\'?[0-9a-zA-Z_])*)(.*)$", "'" + tail) |
| 2180 | collapsed += head + match_literal.group(1).replace("'", "") |
| 2181 | elided = match_literal.group(2) |
| 2182 | else: |
| 2183 | second_quote = tail.find("'") |
| 2184 | if second_quote >= 0: |
| 2185 | collapsed += head + "''" |