如何在Python中正确地添加字符串引号?
我想给一个Python字符串加上一对(双)引号,如果它们缺失的话,但这个字符串里也可能包含引号。
这样做的目的是为了把所有没有被引号包围的命令都加上引号,因为Windows的API在用_popen()执行进程时,需要你把整个命令行用引号包起来。
以下是一些应该加引号的字符串:
<empty string>
type
"type" /?
"type" "/?"
type "a a" b
type "" b
以下是一些不应该加引号的字符串:
"type"
""type" /?"
请务必测试所有示例;判断字符串是否需要引号并不容易。
4 个回答
3
我写了一个简单的状态机,用来跟踪我们是否在一个单词中。如果字符串中的引号深度为零,那我们就需要引号:
def quotify(s):
if s == "":
return '""'
depth = 0
in_word = False
needs_quotes = False
for c in s:
if c == '"':
if in_word:
depth -= 1
else:
depth += 1
else:
if depth == 0:
needs_quotes = True
break
in_word = not c.isspace()
if needs_quotes:
return '"' + s + '"'
else:
return s
assert quotify('') == '""'
assert quotify('''type''') == '''"type"'''
assert quotify('''"type" /?''') == '''""type" /?"'''
assert quotify('''"type" "/?"''') == '''""type" "/?""'''
assert quotify('''type "a a" b''') == '''"type "a a" b"'''
assert quotify('''type "" b''') == '''"type "" b"'''
assert quotify('''"type"''') == '''"type"'''
assert quotify('''""type" /?"''') == '''""type" /?"'''
8
你的问题不一致。
考虑这两种情况:
""a" b"
"a" "b"
第一种情况被理解为一个带有“嵌套引号”的预先引用字符串,而第二种情况则被理解为两个单独的引用字符串。下面是一些例子,能更好地说明这个问题。
" "a" "b" "
" "a" b"
"a ""b"
这些应该如何处理呢?
4
我觉得这个问题很难准确地说明,但也许这个方法可以接近你的目标。
基本的想法是创建一个原始字符串的副本,同时去掉内部引用的内容。这里的内部引用内容是指至少要包含一个非空格字符的部分。
在去掉内部引用的内容后,你再检查一下整个字符串是否需要加上引号。
import re
tests = [
# Test data in original question.
( '', '""' ),
( 'a', '"a"' ),
( '"a"', '"a"' ), # No change.
( '""a" b"', '""a" b"' ), # No change.
( '"a" b', '""a" b"' ),
( '"a" "b"', '""a" "b""' ),
( 'a "b" c', '"a "b" c"' ),
# Test data in latest edits.
( 'type', '"type"' ), # Quote these.
( '"type" /?', '""type" /?"' ),
( '"type" "/?"', '""type" "/?""' ),
( 'type "a a" b', '"type "a a" b"' ),
( 'type "" b', '"type "" b"' ),
( '"type"', '"type"' ), # Don't quote.
( '""type" /?"', '""type" /?"' ),
# Some more tests.
( '"a b" "c d"', '""a b" "c d""' ),
( '" a " foo " b "', '"" a " foo " b ""' ),
]
Q = '"'
re_quoted_items = re.compile(r'" \s* [^"\s] [^"]* \"', re.VERBOSE)
for orig, expected in tests:
# The orig string w/o the internally quoted items.
woqi = re_quoted_items.sub('', orig)
if len(orig) == 0:
orig_quoted = Q + orig + Q
elif len(woqi) > 0 and not (woqi[0] == Q and woqi[-1] == Q):
orig_quoted = Q + orig + Q
else:
orig_quoted = orig
print orig_quoted == expected