@@ -215,12 +215,16 @@ def _guess_quote_and_delimiter(self, data, delimiters):
215215 this way.
216216 """
217217
218+ # The body of a quoted field ends at the first quote which is
219+ # not doubled, as it does for a reader. A lazy ".*?" scans to
220+ # the end of the sample instead, from every start: quadratically.
221+ body = r'(?:(?P=quote){2}|(?!(?P=quote)).)*+'
218222 matches = []
219- for restr in (r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*? (?P=quote)(?P=delim)' , # ,".*? ",
220- r'(?:^|\n)(?P<quote>["\']).*? (?P=quote)(?P<delim>[^\w\n"\'])(?P<space> ?)' , # ".*? ",
221- r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*? (?P=quote)(?:$|\n)' , # ,".*? "
222- r'(?:^|\n)(?P<quote>["\']).*? (?P=quote)(?:$|\n)' ): # ".*? " (no delim, no space)
223- regexp = re .compile (restr , re .DOTALL | re .MULTILINE )
223+ for restr in (r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\'])%s (?P=quote)(?P=delim)' , # ,"... ",
224+ r'(?:^|\n)(?P<quote>["\'])%s (?P=quote)(?P<delim>[^\w\n"\'])(?P<space> ?)' , # "... ",
225+ r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\'])%s (?P=quote)(?:$|\n)' , # ,"... "
226+ r'(?:^|\n)(?P<quote>["\'])%s (?P=quote)(?:$|\n)' ): # "... " (no delim, no space)
227+ regexp = re .compile (restr % body , re .DOTALL | re .MULTILINE )
224228 matches = regexp .findall (data )
225229 if matches :
226230 break
0 commit comments