How to properly add quotes to a string using python?
I want to add a set of (double) quotes to a python string if they are missing but the string can also contain quotes.
The purpose of this is to quote all command that are not already quoted because Windows API requires you to quote the entire command line when you execute a process using _popen().
Here are some strings that should be quoted:
<empty string>
type
"type" /?
"type" "/?"
type "a a" b
type "" b
Here are some that should not be quoted:
"type"
""type" /?"
Please take the 开发者_如何转开发time to test all examples; it is not too easy to detect if the string needs the quotes or not.
Your problem is inconsistent.
Consider the two cases
""a" b"
"a" "b"
The former is interpreted as a pre-quoted string with 'nested quotes', but the latter is interpreted as separately-quoted strings. Here are some examples that highlight the issue.
" "a" "b" "
" "a" b"
"a ""b"
How should they be treated?
I think this is a difficult question to specify in a precise way, but perhaps this strategy will approximate your goal.
The basic idea is to create a copy of the original string, removing the internally quoted items. An internally quoted item is defined here so that it must contains at least one non-whitespace character.
After the internally quoted items have been removed, you then check whether the entire string needs surrounding quotes or not.
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
I wrote a simple state machine to track if we are in a word or not. If the quote depth is ever zero in the string, then we need quotes:
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" /?"'''
You have three cases:
- String is less than two characters long: add quotes
- String has quotes at s[0] and at s[1]: don't add quotes
- Add quotes
And by "add quotes" I mean simply construct '"'+string+'"' and return it.
Translate to if-statements, and you're done.
精彩评论