Как разделить строку с разделителями-запятыми в Python, за исключением запятых, находящихся в кавычках

Я пытаюсь разделить строку с разделителями-запятыми в python. Трудная часть для меня здесь заключается в том, что некоторые из полей в самих данных содержат в себе запятую, и они заключены в кавычки ( " или ' ). Полученная в результате разделительная строка также должна содержать кавычки вокруг удаленных полей. поля могут быть пустыми.

Пример:

 hey,hello,,"hello,world",'hey,world' 

необходимо разделить на 5 частей, как показано ниже

 ['hey', 'hello', '', 'hello,world', 'hey,world'] 

Любые идеи / мысли / предложения / помощь в том, как решить эту проблему в Python, будут высоко оценены.

Благодарю вас, Виш

4 Solutions collect form web for “Как разделить строку с разделителями-запятыми в Python, за исключением запятых, находящихся в кавычках”

(Изменить: исходный ответ имел проблемы с пустыми полями на краях из-за того, как работает re.findall , поэтому я немного re.findall его и добавил тесты.)

 import re def parse_fields(text): r""" >>> list(parse_fields('hey,hello,,"hello,world",\'hey,world\'')) ['hey', 'hello', '', 'hello,world', 'hey,world'] >>> list(parse_fields('hey,hello,,"hello,world",\'hey,world\',')) ['hey', 'hello', '', 'hello,world', 'hey,world', ''] >>> list(parse_fields(',hey,hello,,"hello,world",\'hey,world\',')) ['', 'hey', 'hello', '', 'hello,world', 'hey,world', ''] >>> list(parse_fields('')) [''] >>> list(parse_fields(',')) ['', ''] >>> list(parse_fields('testing,quotes not at "the" beginning \'of\' the,string')) ['testing', 'quotes not at "the" beginning \'of\' the', 'string'] >>> list(parse_fields('testing,"unterminated quotes')) ['testing', '"unterminated quotes'] """ pos = 0 exp = re.compile(r"""(['"]?)(.*?)\1(,|$)""") while True: m = exp.search(text, pos) result = m.group(2) separator = m.group(3) yield result if not separator: break pos = m.end(0) if __name__ == "__main__": import doctest doctest.testmod() 

(['"]?) соответствует необязательной одно- или двухкатегории.

(.*?) соответствует самой строке. Это не жадный матч, чтобы соответствовать столько, сколько необходимо, не съедая целую цепочку. Это присваивается result , и именно это мы и получаем в результате.

\1 – это обратная ссылка, чтобы соответствовать одной и той же одно- или двойной кавычке, которую мы сопоставляли ранее (если она есть).

(,|$) соответствует запятой, разделяющей каждую запись или конец строки. Это назначается separator .

Если разделитель является ложным (например, пустым), это означает, что нет разделителя, поэтому мы находимся в конце строки – мы сделали. В противном случае мы обновляем новую начальную позицию на основе того, где закончилось регулярное выражение ( m.end(0) ), и продолжаем цикл.

Похоже, вам нужен CSV- модуль.

Модуль csv не будет обрабатывать сценарий «и», являясь котировками одновременно. Отсутствие модуля, который обеспечивает такой диалект, нужно получить в бизнесе разбора. Чтобы избежать зависимости от стороннего модуля, мы можем используйте модуль re для выполнения лексического анализа, используя трюк re.MatchObject.lastindex, чтобы связать тип токена с совпадающим шаблоном.

Следующий код при запуске в качестве скрипта передает все показанные тесты с Python 2.7 и 2.2.

 import re # lexical token symbols DQUOTED, SQUOTED, UNQUOTED, COMMA, NEWLINE = xrange(5) _pattern_tuples = ( (r'"[^"]*"', DQUOTED), (r"'[^']*'", SQUOTED), (r",", COMMA), (r"$", NEWLINE), # matches end of string OR \n just before end of string (r"[^,\n]+", UNQUOTED), # order in the above list is important ) _matcher = re.compile( '(' + ')|('.join([i[0] for i in _pattern_tuples]) + ')', ).match _toktype = [None] + [i[1] for i in _pattern_tuples] # need dummy at start because re.MatchObject.lastindex counts from 1 def csv_split(text): """Split a csv string into a list of fields. Fields may be quoted with " or ' or be unquoted. An unquoted string can contain both a " and a ', provided neither is at the start of the string. A trailing \n will be ignored if present. """ fields = [] pos = 0 want_field = True while 1: m = _matcher(text, pos) if not m: raise ValueError("Problem at offset %d in %r" % (pos, text)) ttype = _toktype[m.lastindex] if want_field: if ttype in (DQUOTED, SQUOTED): fields.append(m.group(0)[1:-1]) want_field = False elif ttype == UNQUOTED: fields.append(m.group(0)) want_field = False elif ttype == COMMA: fields.append("") else: assert ttype == NEWLINE fields.append("") break else: if ttype == COMMA: want_field = True elif ttype == NEWLINE: break else: print "*** Error dump ***", ttype, repr(m.group(0)), fields raise ValueError("Missing comma at offset %d in %r" % (pos, text)) pos = m.end(0) return fields if __name__ == "__main__": tests = ( ("""hey,hello,,"hello,world",'hey,world'\n""", ['hey', 'hello', '', 'hello,world', 'hey,world']), ("""\n""", ['']), ("""""", ['']), ("""a,b\n""", ['a', 'b']), ("""a,b""", ['a', 'b']), (""",,,\n""", ['', '', '', '']), ("""a,contains both " and ',c""", ['a', 'contains both " and \'', 'c']), ("""a,'"starts with "...',c""", ['a', '"starts with "...', 'c']), ) for text, expected in tests: result = csv_split(text) print print repr(text) print repr(result) print repr(expected) print result == expected 

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

 def csv_splitter(line): splitthese = [0] splitted = [] splitpos = True for nr, i in enumerate(line): if i == "\"" and splitpos == True: splitpos = False elif i == "\"" and splitpos == False: splitpos = True if i == "," and splitpos == True: splitthese.append(nr) splitthese.append(len(line)+1) for i in range(len(splitthese)-1): splitted.append(re.sub("^,|\"","",line[splitthese[i]:splitthese[i+1]])) return splitted 
  • Pandas - фильтр и регулярное выражение ищут индекс DataFrame
  • регулярное выражение python более одного раза соответствует индексу строки поиска
  • Номер мобильного подтверждения проверки подлинности Python
  • Режимы Python поддерживают что-то вроде Perl \ G?
  • В vs регулярные выражения со списком слов
  • Ли ' +' equal '(a | b) +' в модуле python re?
  • Поиск и замена нескольких строк в xml / текстовых файлах с помощью python
  • Поиск в HTML-строке по строке с регулярным выражением в Python
  • Python - лучший язык программирования в мире.