From 2e0bb0fa9f9fffedecaa1f088f313f6c2d6df965 Mon Sep 17 00:00:00 2001 From: Zsolt Dollenstein Date: Thu, 5 Apr 2018 10:28:46 +0100 Subject: [PATCH 1/1] Handle arbitrary number of backslashes during string normalization (#110) --- black.py | 10 ++++++---- tests/string_quotes.py | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/black.py b/black.py index 2ee7634..9b144ed 100644 --- a/black.py +++ b/black.py @@ -10,6 +10,7 @@ import logging from multiprocessing import Manager import os from pathlib import Path +import re import tokenize import signal import sys @@ -1922,8 +1923,10 @@ def normalize_string_quotes(leaf: Leaf) -> None: prefix = leaf.value[:first_quote_pos] body = leaf.value[first_quote_pos + len(orig_quote):-len(orig_quote)] + unescaped_new_quote = re.compile(r"(([^\\]|^)(\\\\)*)" + new_quote) + escaped_orig_quote = re.compile(r"\\(\\\\)*" + orig_quote) if "r" in prefix.casefold(): - if body.count(new_quote) != body.count(f"\\{new_quote}"): + if unescaped_new_quote.search(body): # There's at least one unescaped new_quote in this raw string # so converting is impossible return @@ -1931,9 +1934,8 @@ def normalize_string_quotes(leaf: Leaf) -> None: # Do not introduce or remove backslashes in raw strings new_body = body else: - new_body = body.replace(f"\\{orig_quote}", orig_quote).replace( - new_quote, f"\\{new_quote}" - ) + new_body = escaped_orig_quote.sub(f"\\1{orig_quote}", body) + new_body = unescaped_new_quote.sub(f"\\1\\\\{new_quote}", new_body) if new_quote == '"""' and new_body[-1] == '"': # edge case: new_body = new_body[:-1] + '\\"' diff --git a/tests/string_quotes.py b/tests/string_quotes.py index f2d720b..c66b6ee 100644 --- a/tests/string_quotes.py +++ b/tests/string_quotes.py @@ -1,3 +1,7 @@ +'\'' +'"' +"'" +"\"" "Hello" "Don't do that" 'Here is a "' @@ -18,9 +22,20 @@ r"raw string ftw" r'Date d\'expiration:(.*)' r'Tricky "quote' r'Not-so-tricky \"quote' +'\n\ +The \"quick\"\n\ +brown fox\n\ +jumps over\n\ +the \'lazy\' dog.\n\ +' +re.compile(r'[\\"]') # output +"'" +'"' +"'" +'"' "Hello" "Don't do that" 'Here is a "' @@ -41,3 +56,10 @@ r"raw string ftw" r"Date d\'expiration:(.*)" r'Tricky "quote' r"Not-so-tricky \"quote" +"\n\ +The \"quick\"\n\ +brown fox\n\ +jumps over\n\ +the 'lazy' dog.\n\ +" +re.compile(r'[\\"]') -- 2.39.5