如何在PyCharm中将所有单引号字符串转换为双引号字符串?

iezvtpos  于 12个月前  发布在  PyCharm
关注(0)|答案(6)|浏览(327)

我想做一些代码清理,并使一个模块中的所有字符串一致地双引号字符串。我的问题是有吨,并通过手工(alt+enter,箭头,回车)是繁琐的,我的regex-Fu是薄弱的。(不断遇到奇怪的情况下,单引号是在文档字符串等)
在Pycharm中有没有更快的方法将所有单引号字符串转换为双引号字符串?

svdrlsy4

svdrlsy41#

Preferences中,在搜索栏中输入double-quoted。这将建议Editor->Intentions。有一个选项可以将双引号字符串转换为单引号字符串,反之亦然。检查此选项以查看是否启用。
当您选择这样一个字符串的一个示例,并单击“灯泡”时,这可能会(也可能不会)为您提供通过点击向右箭头将其应用于整个文件的选项。
如果没有,它至少可以减轻你的痛苦,因为你可以简单地在每个示例上单击一次,然后使用灯泡来修复它。在Intentions上查找文档并不是那么富有成效,关于如何在文件中应用它们或将它们包括在代码检查中。这可能是社区版和完整版之间的区别。
不过,正如@acushner的评论所暗示的那样,根据我的个人经验和偏好,单引号似乎是更常用的风格,可以说是次罗莎佳能。
(To老实说,在这一点上,它是如此根深蒂固,我发现自己的单引号散文。但我认为这是一个个人问题,和TMI。'做你自己。')

mzillmmw

mzillmmw2#

我认为有一个更简单的解决方案没有被讨论,那就是PyCharm的查找和替换功能,它可以忽略注解和字符串字面量,这似乎可以做你想要的事情,而不需要做太多的工作,也没有什么空间来处理边缘情况:

要忽略三重单引号,你可以使用这个正则表达式,它是我从this SO post复制的:

(?<!')'(?!')

字符串


kyxcudwk

kyxcudwk3#

我知道你问过如何在PyCharm中实现它,但我会提出一个工具来代替,因为在我的测试中,它可以正常工作。你仍然可以在PyCharm的终端窗口中运行它,这使得它成为你问题的有效答案;-)。
该工具(源代码如下)基于Python的tokenizer。这保证了只有单引号包围的字符串文字可以被替换。
此外,避免了不直接和安全的转换,甚至可能不需要的转换。报告可能需要手动干预的文件位置。
find命令的帮助下,您可以立即将此工具应用于整个源代码树。

import argparse
import re
from tokenize import generate_tokens, STRING, untokenize

# Tool for the automatic (and manual) conversion of single-quoted strings to double-quoted ones

# Reference for string literals: https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
LONG_STRING_REGEX  = re.compile(r"([fruFRU]*)'''(.*)'''", re.DOTALL)
SHORT_STRING_REGEX = re.compile(r"([fruFRU]*)'(.*)'")  # only if LONG_STRING_REGEX doesn't match

def single_to_double_quotes(infilename, outfilename, long_too):
    convs_done = 0
    manual_conv_starts = []
    output_tokens = []
    with open(infilename) as infile:
        for t in generate_tokens(infile.readline):
            if t.type == STRING:
                if m := LONG_STRING_REGEX.fullmatch(t.string):
                    if long_too:
                        prefix, value = m.groups()
                        if '"""' in value:
                            manual_conv_starts.append(t.start)
                        else:
                            t = (STRING, f'{prefix}"""{value}"""', t.start, t.end, t.line)
                            convs_done += 1
                elif m := SHORT_STRING_REGEX.fullmatch(t.string):
                    prefix, value = m.groups()
                    if '"' in value or "'" in value:
                        manual_conv_starts.append(t.start)
                    else:
                        t = (STRING, f'{prefix}"{value}"', t.start, t.end, t.line)
                        convs_done += 1
            output_tokens.append(t)

    with open(outfilename, 'w') as outfile:
        outfile.write(untokenize(output_tokens))
    return convs_done, manual_conv_starts

parser = argparse.ArgumentParser(description='safely convert single quotes to double quotes')
parser.add_argument('infilename', metavar='INPUT_FILE', help='the input file')
parser.add_argument('outfilename', metavar='OUTPUT_FILE', help='the output file')
parser.add_argument('--long', '-l', action='store_true', help='also convert "long" (triple-quoted) strings')
args = parser.parse_args()  # type: argparse.Namespace
infilename = args.infilename  # type: str
outfilename = args.outfilename  # type: str
long_too = bool(args.long)
print(f"input file: {infilename}")
print(f"long string conversion {('disabled', 'enabled')[long_too]}")
convs_done, manual_conv_starts = single_to_double_quotes(infilename, outfilename, long_too)
print(f"strings converted: {convs_done}")
print(f"possible manual conversions: {len(manual_conv_starts)}")
for start in manual_conv_starts:
    print(f"  {outfilename} line {start[0]} char {start[1] + 1}")
print(f"output file: {outfilename}")

字符串
输出示例(不带-l选项):

input file: single_to_double_quotes_TEST.py
long string conversion disabled
strings converted: 5
possible manual conversions: 3
  single_to_double_quotes_CONV.py line 3 char 5
  single_to_double_quotes_CONV.py line 4 char 5
  single_to_double_quotes_CONV.py line 12 char 7
output file: single_to_double_quotes_CONV.py


single_to_double_quotes_TEST.py

n = 123
s = 'abc'
t = 'd"e"f'
u = 'g\'h\'i'
l = '''
"let's see"
'''
w, x, y, z = '''xyz''', '''"""yz''', '''x"""z''', '''xy"""'''
print(f'{s=}')
d = {'a': 1, 'b': 2, 'c': 3}
print(f"{d['a']=}")
print(f'{d["a"]=}')


single_to_double_quotes_CONV.py

n = 123
s = "abc"
t = 'd"e"f'
u = 'g\'h\'i'
l = '''
"let's see"
'''
w, x, y, z = '''xyz''', '''"""yz''', '''x"""z''', '''xy"""'''
print(f"{s=}")
d = {"a": 1, "b": 2, "c": 3}
print(f"{d['a']=}")
print(f'{d["a"]=}')


在源代码树的副本上,就像在git checkout 时一样,你可以做以下事情:

find . -name \*.py -exec python3 PATH/TO/TOOL.py {} {} \;


这会将每个文件转换为自身。
如果您不熟悉argparse:请从

python3 TOOL.py -h


我建议您修改该工具以最适合您的需要。

2w2cym1i

2w2cym1i4#

这可以使用黑色格式来完成
通过执行pip install black安装黑色
然后执行black .来执行格式化。
这不仅可以处理单引号,还可以将代码格式化为可读性更强的格式。您可以为black提供很多选项来自定义black的格式设置。
您可以在这里查看这些选项:https://black.readthedocs.io/en/stable/usage_and_configuration/the_basics.html#command-line-options

20jt8wwn

20jt8wwn5#

我不知道它是否对任何人都有帮助,但我更喜欢双击选择一个单词,而不是选择引号之间的整个字符串,然后按Alt + Enter。或者反之亦然。你甚至不需要双击,因为Pycharm足够聪明,可以选择第一对引号。我觉得这很舒服。我我不知道它对于非常复杂的嵌套字符串是否足够聪明,但你可以尝试。如果它能让我们选择多行并修复它们,那将是很好的,但这就是黑色在这里的作用,对吗?

zd287kbt

zd287kbt6#

Ctrl+R将弹出查找/替换对话框。只需在查找字段中输入“,在替换字段中输入“。

相关问题