Разделить строку пробелами - с сохранением подстрок в кавычках - в Python

У меня есть такая строка:

this is "a test"

Я пытаюсь написать что-то на Python, чтобы разделить его по пробелам, игнорируя пробелы в кавычках. Результат, который я ищу:

['this','is','a test']

PS. Я знаю, вы спросите: «Что произойдет, если в кавычках есть кавычки, ну, в моем приложении этого никогда не произойдет.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
292
0
97 428
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

Ответ принят как подходящий

Вам нужен split из встроенного модуля shlex.

>>> import shlex
>>> shlex.split('this is "a test"')
['this', 'is', 'a test']

Это должно делать именно то, что вы хотите.

Используйте "posix = False", чтобы сохранить цитаты. shlex.split('this is "a test"', posix=False) возвращает ['this', 'is', '"a test"']

Boon 04.09.2017 05:35

@MatthewG. «Исправление» в Python 2.7.3 означает, что передача строки Unicode в shlex.split() вызовет исключение UnicodeEncodeError.

Rockallite 01.11.2019 06:06

Обратите внимание на модуль shlex, особенно на shlex.split.

>>> import shlex
>>> shlex.split('This is "a test"')
['This', 'is', 'a test']

Вау, впечатляет. Вы написали сообщение одновременно с @Jerub. И через 2 минуты после вопроса!

xaviersjs 10.07.2020 20:04

Попробуй это:

  def adamsplit(s):
    result = []
    inquotes = False
    for substring in s.split('"'):
      if not inquotes:
        result.extend(substring.split())
      else:
        result.append(substring)
      inquotes = not inquotes
    return result

Некоторые тестовые строки:

'This is "a test"' -> ['This', 'is', 'a test']
'"This is \'a test\'"' -> ["This is 'a test'"]

Пожалуйста, укажите повтор строки, которая, по вашему мнению, не будет выполнена.

pjz 23.09.2016 03:04
Считать? adamsplit("This is 'a test'")['This', 'is', "'a", "test'"]
Matthew Schinckel 27.09.2016 07:07

OP говорит только «в кавычках» и имеет только пример с двойными кавычками.

pjz 11.10.2016 16:53

Если вас не интересуют подстроки, чем простой

>>> 'a short sized string with spaces '.split()

Спектакль:

>>> s = " ('a short sized string with spaces '*100).split() "
>>> t = timeit.Timer(stmt=s)
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
171.39 usec/pass

Или строковый модуль

>>> from string import split as stringsplit; 
>>> stringsplit('a short sized string with spaces '*100)

Производительность: похоже, строковый модуль работает лучше, чем строковые методы

>>> s = "stringsplit('a short sized string with spaces '*100)"
>>> t = timeit.Timer(s, "from string import split as stringsplit")
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
154.88 usec/pass

Или вы можете использовать двигатель RE

>>> from re import split as resplit
>>> regex = '\s+'
>>> medstring = 'a short sized string with spaces '*100
>>> resplit(regex, medstring)

Спектакль

>>> s = "resplit(regex, medstring)"
>>> t = timeit.Timer(s, "from re import split as resplit; regex='\s+'; medstring='a short sized string with spaces '*100")
>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000)
540.21 usec/pass

Для очень длинных строк не следует загружать всю строку в память, а вместо этого либо разделять строки, либо использовать итерационный цикл.

Похоже, вы упустили суть вопроса. В строке есть разделы в кавычках, которые не нужно разделять.

rjmunro 01.11.2008 02:08

Поскольку этот вопрос помечен регулярным выражением, я решил попробовать подход с регулярным выражением. Сначала я заменяю все пробелы в частях кавычек на \ x00, затем разделяю пробелами, а затем заменяю \ x00 обратно на пробелы в каждой части.

Обе версии делают то же самое, но splitter немного более читаем, чем splitter2.

import re

s = 'this is "a test" some text "another test"'

def splitter(s):
    def replacer(m):
        return m.group(0).replace(" ", "\x00")
    parts = re.sub('".+?"', replacer, s).split()
    parts = [p.replace("\x00", " ") for p in parts]
    return parts

def splitter2(s):
    return [p.replace("\x00", " ") for p in re.sub('".+?"', lambda m: m.group(0).replace(" ", "\x00"), s).split()]

print splitter2(s)

Вместо этого вам следовало использовать re.Scanner. Это более надежно (и я фактически реализовал шлекс-подобный с помощью re.Scanner).

Devin Jeanpierre 24.03.2009 19:37

+1 Хм, это довольно умная идея - разбить проблему на несколько этапов, чтобы ответ не был слишком сложным. Shlex не сделал именно то, что мне нужно, даже при попытке настроить его. И решения с однопроходным регулярным выражением становились действительно странными и сложными.

leetNightshade 23.07.2013 20:31

Я вижу здесь подходы с регулярными выражениями, которые выглядят сложными и / или неправильными. Это меня удивляет, потому что синтаксис регулярных выражений может легко описывать «пробелы или объекты, заключенные в кавычки», а большинство механизмов регулярных выражений (включая Python) могут разделяться на регулярное выражение. Итак, если вы собираетесь использовать регулярные выражения, почему бы просто не сказать именно то, что вы имеете в виду ?:

test = 'this is "a test"'  # or "this is 'a test'"
# pieces = [p for p in re.split("( |[\\"'].*[\\"'])", test) if p.strip()]
# From comments, use this:
pieces = [p for p in re.split("( |\\".*?\\"|'.*?')", test) if p.strip()]

Объяснение:

[\\"'] = double-quote or single-quote
.* = anything
( |X) = space or X
.strip() = remove space and empty-string separators

Однако shlex, вероятно, предоставляет больше возможностей.

Я думал примерно так же, но предлагал вместо t [t.strip ('"') для t в re.findall (r '[^ \ s"] + | "[^"] * "', 'this is" тест"')]

Darius Bacon 08.02.2009 06:09

Что делает это разделение, когда в двойных кавычках есть апострофы: Он сказал: «Не делай этого!» Я думаю, он будет рассматривать <"Дон" как единое целое, не так ли?

Jonathan Leffler 08.02.2009 06:21

Джонатан: в данном случае нет, я сделал две ошибки, которые в этом случае нивелируют друг друга: жадный. * Выйдет в финал ". :-) Я должен был сказать" (| \\\ ". *? \ \\ "| '. *?')". Хороший улов.

Kate 08.02.2009 06:39

+1 Я использую это, потому что это было чертовски быстрее, чем shlex.

hanleyp 16.11.2009 22:44

+1 от меня, второе регулярное выражение (комментарии) работает для моих нужд, а первое - нет. Таким образом, я редактировал второе регулярное выражение, но оставил первое легко видимым.

user257111 17.03.2010 00:47

P.S. это отлично, мне не нужны функции shlex, просто сплит, как argv. Я бы дал +2, если бы мог.

user257111 17.03.2010 00:47

этот код почти похож на Perl, разве вы не слышали о «сырых строках»?

SpliFF 22.03.2010 09:41

Рассмотрим эти данные: string = r'simple "quot ed" "игнорировать escape-последовательность в кавычках \\" "howboutthemapostrophe \ 's?" "\" withescapedquotes \ "" "\" с несбалансированными экранированными кавычками "'Обновление Jonathan / Kate / Ninefingers разбивает термин withescapedquotes на три (дегенеративные-одиночные цитаты, withescapedquotes, другие-вырожденные). в порядке. Это можно сделать через re?

jackr 25.06.2010 22:55

Почему тройная обратная косая черта? Разве простая обратная косая черта не сделает то же самое?

Doppelganger 13.08.2011 01:20

Этот обрабатывает несбалансированные кавычки и юникод, а shlex - нет :(

lambacck 23.11.2011 22:29

+1 Мне нравится этот ответ, потому что он фактически сохраняет цитаты, в отличие от Шлекса. Сплит Shlex должен делать только расщепление, он не должен удалять цитаты обо мне. Хотя, возможно, это настраивается.

leetNightshade 22.07.2013 19:21

На самом деле, что мне не нравится в этом, так это то, что все, что до / после кавычек, не разделяется должным образом. Если у меня есть такая строка, как "PARAMS val1 =" Thing "val2 =" Thing2 "'. Я ожидаю, что строка разделится на три части, но она разделится на 5. Прошло много времени с тех пор, как я делал регулярные выражения, поэтому я не чувствую, что сейчас пытаюсь решить эту проблему с помощью вашего решения.

leetNightshade 23.07.2013 04:00

При использовании регулярных выражений следует использовать необработанные строки.

asmeurer 19.12.2013 06:29

Он обрабатывает оба типа кавычек и удаляет только проанализированный: [''.join(t) for t in re.findall(r"""([^\s"']+)|"([^"]*)"|'([^']*)'""", test)]

MortenB 26.05.2016 17:50

Чтобы использовать любой разделитель (не только пробелы) и исправить проблему неправильного разделения до / после кавычек, посмотрите здесь stackoverflow.com/a/56791724/1201614

luca 29.06.2019 13:33

Может ли кто-нибудь расширить данное «объяснение»? Мне достаточно удобно с регулярным выражением, но я не понял «объяснения». Может ли кто-нибудь предоставить здесь более подробную информацию? Похоже, это было бы моим предпочтительным решением, за исключением того, что мне это непонятно.

SherylHohman 01.04.2020 22:17

В зависимости от вашего варианта использования вы также можете проверить модуль csv:

import csv
lines = ['this is "a string"', 'and more "stuff"']
for row in csv.reader(lines, delimiter = " "):
    print(row)

Выход:

['this', 'is', 'a string']
['and', 'more', 'stuff']

полезно, когда shlex удаляет некоторые необходимые символы

scraplesh 29.03.2013 22:08

CSV используйте две двойные кавычки подряд (как рядом, "") для представления одной двойной кавычки ", поэтому превратит две двойные кавычки в одинарную кавычку 'this is "a string""' и 'this is "a string"""' будут отображаться на ['this', 'is', 'a string"']

Boris 01.11.2019 02:45

Хм, похоже, не удается найти кнопку «Ответить» ... в любом случае, этот ответ основан на подходе Кейт, но правильно разбивает строки на подстроки, содержащие экранированные кавычки, а также удаляет начальные и конечные кавычки подстрок:

  [i.strip('"').strip("'") for i in re.split(r'(\s+|(?<!\)".*?(?<!\)"|(?<!\)\'.*?(?<!\)\')', string) if i.strip()]

Это работает со строками, такими как 'This is " a \\"test\\"\\'s substring"' (безумная разметка, к сожалению, необходима, чтобы Python не удалял escape-последовательности).

Если результирующие escape-последовательности в строках в возвращаемом списке не нужны, вы можете использовать эту слегка измененную версию функции:

[i.strip('"').strip("'").decode('string_escape') for i in re.split(r'(\s+|(?<!\)".*?(?<!\)"|(?<!\)\'.*?(?<!\)\')', string) if i.strip()]

Чтобы обойти проблемы с Unicode в некоторых версиях Python 2, я предлагаю:

from shlex import split as _split
split = lambda a: [b.decode('utf-8') for b in _split(a.encode('utf-8'))]

Для python 2.7.5 это должно быть: split = lambda a: [b.decode('utf-8') for b in _split(a)], иначе вы получите: UnicodeDecodeError: 'ascii' codec can't decode byte ... in position ...: ordinal not in range(128)

Peter Varo 27.06.2013 04:43

Я использую shlex.split для обработки 70 000 000 строк журнала Squid, он такой медленный. Так что я перешел на re.

Пожалуйста, попробуйте это, если у вас проблемы с производительностью с shlex.

import re

def line_split(line):
    return re.findall(r'[^"\s]\S*|".+?"', line)

Я предлагаю:

тестовая строка:

s = 'abc "ad" \'fg\' "kk\'rdt\'" zzz"34"zzz "" \'\''

захватить также "" и "':

import re
re.findall(r'"[^"]*"|\'[^\']*\'|[^"\'\s]+',s)

результат:

['abc', '"ad"', "'fg'", '"kk\'rdt\'"', 'zzz', '"34"', 'zzz', '""', "''"]

игнорировать пустые "" и "':

import re
re.findall(r'"[^"]+"|\'[^\']+\'|[^"\'\s]+',s)

результат:

['abc', '"ad"', "'fg'", '"kk\'rdt\'"', 'zzz', '"34"', 'zzz']

Также может быть написано как re.findall("(?:\".*?\"|'.*?'|[^\s'\"]+)", s).

hochl 08.11.2018 18:18

Для сохранения кавычек используйте эту функцию:

def getArgs(s):
    args = []
    cur = ''
    inQuotes = 0
    for char in s.strip():
        if char == ' ' and not inQuotes:
            args.append(cur)
            cur = ''
        elif char == '"' and not inQuotes:
            inQuotes = 1
            cur += char
        elif char == '"' and inQuotes:
            inQuotes = 0
            cur += char
        else:
            cur += char
    args.append(cur)
    return args

При сравнении с большей строкой ваша функция настолько медленная

FaranAiki 23.12.2019 17:20

Тест скорости разных ответов:

import re
import shlex
import csv

line = 'this is "a test"'

%timeit [p for p in re.split("( |\\".*?\\"|'.*?')", line) if p.strip()]
100000 loops, best of 3: 5.17 µs per loop

%timeit re.findall(r'[^"\s]\S*|".+?"', line)
100000 loops, best of 3: 2.88 µs per loop

%timeit list(csv.reader([line], delimiter = " "))
The slowest run took 9.62 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 2.4 µs per loop

%timeit shlex.split(line)
10000 loops, best of 3: 50.2 µs per loop

Основная проблема с принятым подходом shlex заключается в том, что он не игнорирует escape-символы за пределами цитируемых подстрок и дает несколько неожиданные результаты в некоторых угловых случаях.

У меня есть следующий вариант использования, когда мне нужна функция разделения, которая разделяет входные строки таким образом, чтобы сохранялись подстроки в одинарных или двойных кавычках, с возможностью экранирования кавычек внутри такой подстроки. Кавычки внутри строки без кавычек не должны обрабатываться иначе, чем любой другой символ. Некоторые примеры тестовых случаев с ожидаемым результатом:

 input string        | expected output
===============================================
 'abc def'           | ['abc', 'def']
 "abc \s def"       | ['abc', '\s', 'def']
 '"abc def" ghi'     | ['abc def', 'ghi']
 "'abc def' ghi"     | ['abc def', 'ghi']
 '"abc \" def" ghi' | ['abc " def', 'ghi']
 "'abc \' def' ghi" | ["abc ' def", 'ghi']
 "'abc \s def' ghi" | ['abc \s def', 'ghi']
 '"abc \s def" ghi' | ['abc \s def', 'ghi']
 '"" test'           | ['', 'test']
 "'' test"           | ['', 'test']
 "abc'def"           | ["abc'def"]
 "abc'def'"          | ["abc'def'"]
 "abc'def' ghi"      | ["abc'def'", 'ghi']
 "abc'def'ghi"       | ["abc'def'ghi"]
 'abc"def'           | ['abc"def']
 'abc"def"'          | ['abc"def"']
 'abc"def" ghi'      | ['abc"def"', 'ghi']
 'abc"def"ghi'       | ['abc"def"ghi']
 "r'AA' r'.*_xyz$'"  | ["r'AA'", "r'.*_xyz$'"]

В итоге я получил следующую функцию для разделения строки таким образом, чтобы ожидаемые выходные результаты были для всех входных строк:

import re

def quoted_split(s):
    def strip_quotes(s):
        if s and (s[0] == '"' or s[0] == "'") and s[0] == s[-1]:
            return s[1:-1]
        return s
    return [strip_quotes(p).replace('\"', '"').replace("\'", "'") \
            for p in re.findall(r'"(?:\.|[^"])*"|\'(?:\.|[^\'])*\'|[^\s]+', s)]

Следующее тестовое приложение проверяет результаты других подходов (на данный момент shlex и csv) и реализации пользовательского разделения:

#!/bin/python2.7

import csv
import re
import shlex

from timeit import timeit

def test_case(fn, s, expected):
    try:
        if fn(s) == expected:
            print '[ OK ] %s -> %s' % (s, fn(s))
        else:
            print '[FAIL] %s -> %s' % (s, fn(s))
    except Exception as e:
        print '[FAIL] %s -> exception: %s' % (s, e)

def test_case_no_output(fn, s, expected):
    try:
        fn(s)
    except:
        pass

def test_split(fn, test_case_fn=test_case):
    test_case_fn(fn, 'abc def', ['abc', 'def'])
    test_case_fn(fn, "abc \s def", ['abc', '\s', 'def'])
    test_case_fn(fn, '"abc def" ghi', ['abc def', 'ghi'])
    test_case_fn(fn, "'abc def' ghi", ['abc def', 'ghi'])
    test_case_fn(fn, '"abc \" def" ghi', ['abc " def', 'ghi'])
    test_case_fn(fn, "'abc \' def' ghi", ["abc ' def", 'ghi'])
    test_case_fn(fn, "'abc \s def' ghi", ['abc \s def', 'ghi'])
    test_case_fn(fn, '"abc \s def" ghi', ['abc \s def', 'ghi'])
    test_case_fn(fn, '"" test', ['', 'test'])
    test_case_fn(fn, "'' test", ['', 'test'])
    test_case_fn(fn, "abc'def", ["abc'def"])
    test_case_fn(fn, "abc'def'", ["abc'def'"])
    test_case_fn(fn, "abc'def' ghi", ["abc'def'", 'ghi'])
    test_case_fn(fn, "abc'def'ghi", ["abc'def'ghi"])
    test_case_fn(fn, 'abc"def', ['abc"def'])
    test_case_fn(fn, 'abc"def"', ['abc"def"'])
    test_case_fn(fn, 'abc"def" ghi', ['abc"def"', 'ghi'])
    test_case_fn(fn, 'abc"def"ghi', ['abc"def"ghi'])
    test_case_fn(fn, "r'AA' r'.*_xyz$'", ["r'AA'", "r'.*_xyz$'"])

def csv_split(s):
    return list(csv.reader([s], delimiter=' '))[0]

def re_split(s):
    def strip_quotes(s):
        if s and (s[0] == '"' or s[0] == "'") and s[0] == s[-1]:
            return s[1:-1]
        return s
    return [strip_quotes(p).replace('\"', '"').replace("\'", "'") for p in re.findall(r'"(?:\.|[^"])*"|\'(?:\.|[^\'])*\'|[^\s]+', s)]

if __name__ == '__main__':
    print 'shlex\n'
    test_split(shlex.split)
    print

    print 'csv\n'
    test_split(csv_split)
    print

    print 're\n'
    test_split(re_split)
    print

    iterations = 100
    setup = 'from __main__ import test_split, test_case_no_output, csv_split, re_split\nimport shlex, re'
    def benchmark(method, code):
        print '%s: %.3fms per iteration' % (method, (1000 * timeit(code, setup=setup, number=iterations) / iterations))
    benchmark('shlex', 'test_split(shlex.split, test_case_no_output)')
    benchmark('csv', 'test_split(csv_split, test_case_no_output)')
    benchmark('re', 'test_split(re_split, test_case_no_output)')

Выход:

shlex

[ OK ] abc def -> ['abc', 'def']
[FAIL] abc \s def -> ['abc', 's', 'def']
[ OK ] "abc def" ghi -> ['abc def', 'ghi']
[ OK ] 'abc def' ghi -> ['abc def', 'ghi']
[ OK ] "abc \" def" ghi -> ['abc " def', 'ghi']
[FAIL] 'abc \' def' ghi -> exception: No closing quotation
[ OK ] 'abc \s def' ghi -> ['abc \s def', 'ghi']
[ OK ] "abc \s def" ghi -> ['abc \s def', 'ghi']
[ OK ] "" test -> ['', 'test']
[ OK ] '' test -> ['', 'test']
[FAIL] abc'def -> exception: No closing quotation
[FAIL] abc'def' -> ['abcdef']
[FAIL] abc'def' ghi -> ['abcdef', 'ghi']
[FAIL] abc'def'ghi -> ['abcdefghi']
[FAIL] abc"def -> exception: No closing quotation
[FAIL] abc"def" -> ['abcdef']
[FAIL] abc"def" ghi -> ['abcdef', 'ghi']
[FAIL] abc"def"ghi -> ['abcdefghi']
[FAIL] r'AA' r'.*_xyz$' -> ['rAA', 'r.*_xyz$']

csv

[ OK ] abc def -> ['abc', 'def']
[ OK ] abc \s def -> ['abc', '\s', 'def']
[ OK ] "abc def" ghi -> ['abc def', 'ghi']
[FAIL] 'abc def' ghi -> ["'abc", "def'", 'ghi']
[FAIL] "abc \" def" ghi -> ['abc \', 'def"', 'ghi']
[FAIL] 'abc \' def' ghi -> ["'abc", "\'", "def'", 'ghi']
[FAIL] 'abc \s def' ghi -> ["'abc", '\s', "def'", 'ghi']
[ OK ] "abc \s def" ghi -> ['abc \s def', 'ghi']
[ OK ] "" test -> ['', 'test']
[FAIL] '' test -> ["''", 'test']
[ OK ] abc'def -> ["abc'def"]
[ OK ] abc'def' -> ["abc'def'"]
[ OK ] abc'def' ghi -> ["abc'def'", 'ghi']
[ OK ] abc'def'ghi -> ["abc'def'ghi"]
[ OK ] abc"def -> ['abc"def']
[ OK ] abc"def" -> ['abc"def"']
[ OK ] abc"def" ghi -> ['abc"def"', 'ghi']
[ OK ] abc"def"ghi -> ['abc"def"ghi']
[ OK ] r'AA' r'.*_xyz$' -> ["r'AA'", "r'.*_xyz$'"]

re

[ OK ] abc def -> ['abc', 'def']
[ OK ] abc \s def -> ['abc', '\s', 'def']
[ OK ] "abc def" ghi -> ['abc def', 'ghi']
[ OK ] 'abc def' ghi -> ['abc def', 'ghi']
[ OK ] "abc \" def" ghi -> ['abc " def', 'ghi']
[ OK ] 'abc \' def' ghi -> ["abc ' def", 'ghi']
[ OK ] 'abc \s def' ghi -> ['abc \s def', 'ghi']
[ OK ] "abc \s def" ghi -> ['abc \s def', 'ghi']
[ OK ] "" test -> ['', 'test']
[ OK ] '' test -> ['', 'test']
[ OK ] abc'def -> ["abc'def"]
[ OK ] abc'def' -> ["abc'def'"]
[ OK ] abc'def' ghi -> ["abc'def'", 'ghi']
[ OK ] abc'def'ghi -> ["abc'def'ghi"]
[ OK ] abc"def -> ['abc"def']
[ OK ] abc"def" -> ['abc"def"']
[ OK ] abc"def" ghi -> ['abc"def"', 'ghi']
[ OK ] abc"def"ghi -> ['abc"def"ghi']
[ OK ] r'AA' r'.*_xyz$' -> ["r'AA'", "r'.*_xyz$'"]

shlex: 0.281ms per iteration
csv: 0.030ms per iteration
re: 0.049ms per iteration

Таким образом, производительность намного лучше, чем у shlex, и ее можно дополнительно улучшить, предварительно скомпилировав регулярное выражение, и в этом случае он превзойдет подход csv.

Не уверен, о чем вы говорите: `` `>>> shlex.split ('это" тест ") [' это ',' is ',' тест '] >>> shlex.split (' this is \\ "тест \\" ') [' this ',' is ',' "a ',' test" '] >>> shlex.split (' this is "\\" test \\ " "') [' this ',' is ',' a" test "']` ``

morsik 15.05.2019 19:27

@morsik, о чем ты? Может быть, ваш вариант использования не соответствует моему? Когда вы посмотрите на тестовые примеры, вы увидите все случаи, когда shlex ведет себя не так, как ожидалось для моих вариантов использования.

Ton van den Heuvel 15.05.2019 19:35

Похоже, что по соображениям производительности re быстрее. Вот мое решение с использованием наименее жадного оператора, сохраняющего внешние кавычки:

re.findall("(?:\".*?\"|\S)+", s)

Результат:

['this', 'is', '"a test"']

Он оставляет вместе такие конструкции, как aaa"bla blub"bbb, поскольку эти токены не разделены пробелами. Если строка содержит экранированные символы, вы можете сопоставить это так:

>>> a = "She said \"He said, \\"My name is Mark.\\"\""
>>> a
'She said "He said, \"My name is Mark.\""'
>>> for i in re.findall("(?:\".*?[^\\]\"|\S)+", a): print(i)
...
She
said
"He said, \"My name is Mark.\""

Обратите внимание, что это также соответствует пустой строке "" посредством части \S шаблона.

Еще одним важным преимуществом этого решения является его универсальность в отношении символа-разделителя (например, , через '(?:".*?"|[^,])+'). То же самое относится к кавычкам (заключительным) символам.

a_guest 05.06.2019 16:24

Как вариант попробуйте tssplit:

In [1]: from tssplit import tssplit
In [2]: tssplit('this is "a test"', quote='"', delimiter='')
Out[2]: ['this', 'is', 'a test']

Другие вопросы по теме