]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-103925: Fix csv.Sniffer for a quoted field ending a CRLF line (GH-103926...
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 21 Jul 2026 06:04:22 +0000 (09:04 +0300)
committerGitHub <noreply@github.com>
Tue, 21 Jul 2026 06:04:22 +0000 (06:04 +0000)
"$" does not match before "\r" even in the MULTILINE mode, so such a
field was not found and the delimiter was guessed from character
frequencies instead, which could give a letter.

(cherry picked from commit 70f7c6c0f2ddfd3b447946f1b926776b2a344703)

Co-authored-by: Zhou Wei <lilaboc.cn@gmail.com>
Lib/csv.py
Lib/test/test_csv.py
Misc/NEWS.d/next/Library/2023-04-27-14-50-03.gh-issue-103925.khC-El.rst [new file with mode: 0644]

index cd202659873811a2ea47c7374cc268d26a9ac5f3..b73ad049d98166506c06791eb34d245185dc96a4 100644 (file)
@@ -283,10 +283,10 @@ class Sniffer:
         """
 
         matches = []
-        for restr in (r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?P=delim)', # ,".*?",
-                      r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?P<delim>[^\w\n"\'])(?P<space> ?)',   #  ".*?",
-                      r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?:$|\n)',   # ,".*?"
-                      r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?:$|\n)'):                            #  ".*?" (no delim, no space)
+        for restr in (r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?P=delim)',   # ,".*?",
+                      r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?P<delim>[^\w\n"\'])(?P<space> ?)',     #  ".*?",
+                      r'(?P<delim>[^\w\n"\'])(?P<space> ?)(?P<quote>["\']).*?(?P=quote)(?:$|\r|\n)',  # ,".*?"
+                      r'(?:^|\n)(?P<quote>["\']).*?(?P=quote)(?:$|\r|\n)'):                           #  ".*?" (no delim, no space)
             regexp = re.compile(restr, re.DOTALL | re.MULTILINE)
             matches = regexp.findall(data)
             if matches:
index 6ea388313bbfd4924194bd806581dd03b2b944c0..b6e578c40e7471db875aa08a7a65f6bde303a49e 100644 (file)
@@ -1357,6 +1357,9 @@ ghijkl\0mno
 ghi\0jkl
 """
 
+    sample19 = ('time,title\r\n'
+                '2020-10-01,"Pocket - Save news, videos, stories and more"\r\n')
+
     def test_issue43625(self):
         sniffer = csv.Sniffer()
         self.assertTrue(sniffer.has_header(self.sample12))
@@ -1427,6 +1430,9 @@ ghi\0jkl
         self.assertEqual(dialect.quotechar, "'")
         dialect = sniffer.sniff(self.sample14)
         self.assertEqual(dialect.delimiter, '\0')
+        dialect = sniffer.sniff(self.sample19)
+        self.assertEqual(dialect.delimiter, ',')
+        self.assertEqual(dialect.quotechar, '"')
 
     def test_doublequote(self):
         sniffer = csv.Sniffer()
diff --git a/Misc/NEWS.d/next/Library/2023-04-27-14-50-03.gh-issue-103925.khC-El.rst b/Misc/NEWS.d/next/Library/2023-04-27-14-50-03.gh-issue-103925.khC-El.rst
new file mode 100644 (file)
index 0000000..858ce6e
--- /dev/null
@@ -0,0 +1,3 @@
+Fix :meth:`csv.Sniffer.sniff` for a sample with ``\r\n`` line endings in
+which a quoted field ends a line: a letter could be detected as the
+delimiter.