Python: Розділити змішану String

Я читаю ряд рядків з файлу у такому вигляді:

line = a   b  c  d,e,f    g   h  i,j,k,l   m   n

Що я хочу, це рядки без "," - розділених елементів, наприклад,

a   b  c  d    g   h  i   m   n 
a   b  c  d    g   h  j   m   n
a   b  c  d    g   h  k   m   n
a   b  c  d    g   h  l   m   n
a   b  c  e    g   h  i   m   n
a   b  c  e    g   h  j   m   n
a   b  c  e    g   h  k   m   n
a   b  c  e    g   h  l   m   n
.   .  .  .    .   .  .   .   .
.   .  .  .    .   .  .   .   .

First I would split line

sline = line.split()

Тепер я мав би пройти над sline і шукати елементи, які можна розділити з "," як роздільник. Проблема полягає в тому, що я не завжди знаю, скільки з тих елементів, які я повинен очікувати. Будь-які ідеї?

3
@Tengis: чи могли б ви прояснити своє питання, будь ласка? Ваш текст говорить про те, що ви просто хочете видалити будь-яку частину поля після коми. Але ваш приклад, здається, показує, що ви хочете розгорнути будь-яке поле, розділене комами, на кілька рядків. Так що це, будь ласка
додано Автор MiniQuark, джерело
@Tengis: чи могли б ви прояснити своє питання, будь ласка? Ваш текст говорить про те, що ви просто хочете видалити будь-яку частину поля після коми. Але ваш приклад, здається, показує, що ви хочете розгорнути будь-яке поле, розділене комами, на кілька рядків. Так що це, будь ласка
додано Автор MiniQuark, джерело
Отже, ви хочете вилучити коми та елемент після нього? Як довго (у символах) це може бути? Чи може бути пробіл між комою та елементом?
додано Автор soon, джерело
Отже, ви хочете вилучити коми та елемент після нього? Як довго (у символах) це може бути? Чи може бути пробіл між комою та елементом?
додано Автор soon, джерело
Це виглядає так, як вам потрібно повторити твій рядок для кожного елемента, розділеного , . Я правильно
додано Автор oleg, джерело
Це виглядає так, як вам потрібно повторити твій рядок для кожного елемента, розділеного , . Я правильно
додано Автор oleg, джерело

8 Відповіді

Ваше запитання не дуже зрозуміле. Якщо ви хочете позбавити будь-яку частину після комами (як показує ваш текст), то слід робити досить читабельний лайнер:

cleaned_line = " ".join([field.split(",")[0] for field in line.split()])

Якщо ви хочете розгорнути рядків із полями, розділеними комами, на кілька рядків (як показує ваш приклад), то слід використовувати функцію itertools.product :

import itertools
line = "a   b  c  d,e,f    g   h  i,j,k,l   m   n"
line_fields = [field.split(",") for field in line.split()]
for expanded_line_fields in itertools.product(*line_fields):
    print " ".join(expanded_line_fields)

Це висновок:

a b c d g h i m n
a b c d g h j m n
a b c d g h k m n
a b c d g h l m n
a b c e g h i m n
a b c e g h j m n
a b c e g h k m n
a b c e g h l m n
a b c f g h i m n
a b c f g h j m n
a b c f g h k m n
a b c f g h l m n

Якщо для чогось важливо зберегти початковий інтервал , то ви можете замінити line.split() на re.findall ("([^] * | *) ", рядок) :

import re
import itertools
line = "a   b  c  d,e,f    g   h  i,j,k,l   m   n"
line_fields = [field.split(",") for field in re.findall("([^ ]+| +)", line)]
for expanded_line_fields in itertools.product(*line_fields):
    print "".join(expanded_line_fields)

Це висновок:

a   b  c  d    g   h  i   m   n
a   b  c  d    g   h  j   m   n
a   b  c  d    g   h  k   m   n
a   b  c  d    g   h  l   m   n
a   b  c  e    g   h  i   m   n
a   b  c  e    g   h  j   m   n
a   b  c  e    g   h  k   m   n
a   b  c  e    g   h  l   m   n
a   b  c  f    g   h  i   m   n
a   b  c  f    g   h  j   m   n
a   b  c  f    g   h  k   m   n
a   b  c  f    g   h  l   m   n
3
додано
Оновлений відповідь, щоб зберегти оригінальний інтервал.
додано Автор MiniQuark, джерело
Я оновив мою відповідь, щоб враховувати обидва інтерпретації питання.
додано Автор MiniQuark, джерело
О хлопчисько, я бачу, що ти маєш на увазі. Однак це не так, як я зрозумів це питання. Я думаю, ти правий, але я попрошу Тенгіса пояснити. Він повинен був сказати щось на кшталт "розширити поля, розділені комою".
додано Автор MiniQuark, джерело
@Максим: Я думаю, це робить. "a b c d, e, f g h" => "a b c d h h"
додано Автор MiniQuark, джерело
Ні. У першому рядку потрібно надрукувати "a b c d h h", а потім "a b c e g h" і "a b c f g h".
додано Автор Maxime Chéramy, джерело
Я думаю, що це не відповідає на питання (див. Приклад).
додано Автор Maxime Chéramy, джерело

Ваше запитання не дуже зрозуміле. Якщо ви хочете позбавити будь-яку частину після комами (як показує ваш текст), то слід робити досить читабельний лайнер:

cleaned_line = " ".join([field.split(",")[0] for field in line.split()])

Якщо ви хочете розгорнути рядків із полями, розділеними комами, на кілька рядків (як показує ваш приклад), то слід використовувати функцію itertools.product :

import itertools
line = "a   b  c  d,e,f    g   h  i,j,k,l   m   n"
line_fields = [field.split(",") for field in line.split()]
for expanded_line_fields in itertools.product(*line_fields):
    print " ".join(expanded_line_fields)

Це висновок:

a b c d g h i m n
a b c d g h j m n
a b c d g h k m n
a b c d g h l m n
a b c e g h i m n
a b c e g h j m n
a b c e g h k m n
a b c e g h l m n
a b c f g h i m n
a b c f g h j m n
a b c f g h k m n
a b c f g h l m n

Якщо для чогось важливо зберегти початковий інтервал , то ви можете замінити line.split() на re.findall ("([^] * | *) ", рядок) :

import re
import itertools
line = "a   b  c  d,e,f    g   h  i,j,k,l   m   n"
line_fields = [field.split(",") for field in re.findall("([^ ]+| +)", line)]
for expanded_line_fields in itertools.product(*line_fields):
    print "".join(expanded_line_fields)

Це висновок:

a   b  c  d    g   h  i   m   n
a   b  c  d    g   h  j   m   n
a   b  c  d    g   h  k   m   n
a   b  c  d    g   h  l   m   n
a   b  c  e    g   h  i   m   n
a   b  c  e    g   h  j   m   n
a   b  c  e    g   h  k   m   n
a   b  c  e    g   h  l   m   n
a   b  c  f    g   h  i   m   n
a   b  c  f    g   h  j   m   n
a   b  c  f    g   h  k   m   n
a   b  c  f    g   h  l   m   n
3
додано
Я оновив мою відповідь, щоб враховувати обидва інтерпретації питання.
додано Автор MiniQuark, джерело
Оновлений відповідь, щоб зберегти оригінальний інтервал.
додано Автор MiniQuark, джерело
О хлопчисько, я бачу, що ти маєш на увазі. Однак це не так, як я зрозумів це питання. Я думаю, ти правий, але я попрошу Тенгіса пояснити. Він повинен був сказати щось на кшталт "розширити поля, розділені комою".
додано Автор MiniQuark, джерело
@Максим: Я думаю, це робить. "a b c d, e, f g h" => "a b c d h h"
додано Автор MiniQuark, джерело
Я думаю, що це не відповідає на питання (див. Приклад).
додано Автор Maxime Chéramy, джерело
Ні. У першому рядку потрібно надрукувати "a b c d h h", а потім "a b c e g h" і "a b c f g h".
додано Автор Maxime Chéramy, джерело

Використовуючи regex , itertools.product та деяке форматування рядка:

Це рішення також зберігає початковий інтервал.

>>> import re
>>> from itertools import product
>>> line = 'a   b  c  d,e,f    g   h  i,j,k,l   m   n'
>>> items = [x[0].split(',') for x in re.findall(r'((\w+,)+\w)',line)]
>>> strs = re.sub(r'((\w+,)+\w+)','{}',line)
>>> for prod in product(*items):
...     print (strs.format(*prod))
...     
a   b  c  d    g   h  i   m   n
a   b  c  d    g   h  j   m   n
a   b  c  d    g   h  k   m   n
a   b  c  d    g   h  l   m   n
a   b  c  e    g   h  i   m   n
a   b  c  e    g   h  j   m   n
a   b  c  e    g   h  k   m   n
a   b  c  e    g   h  l   m   n
a   b  c  f    g   h  i   m   n
a   b  c  f    g   h  j   m   n
a   b  c  f    g   h  k   m   n
a   b  c  f    g   h  l   m   n

Інший приклад:

>>> line = 'a   b  c  d,e,f    g   h  i,j,k,l   m   n q,w,e,r  f o   o'
>>> items = [x[0].split(',') for x in re.findall(r'((\w+,)+\w)',line)]
>>> strs = re.sub(r'((\w+,)+\w+)','{}',line)
for prod in product(*items):
    print (strs.format(*prod))
...     
a   b  c  d    g   h  i   m   n q  f o   o
a   b  c  d    g   h  i   m   n w  f o   o
a   b  c  d    g   h  i   m   n e  f o   o
a   b  c  d    g   h  i   m   n r  f o   o
a   b  c  d    g   h  j   m   n q  f o   o
a   b  c  d    g   h  j   m   n w  f o   o
a   b  c  d    g   h  j   m   n e  f o   o
a   b  c  d    g   h  j   m   n r  f o   o
a   b  c  d    g   h  k   m   n q  f o   o
a   b  c  d    g   h  k   m   n w  f o   o
a   b  c  d    g   h  k   m   n e  f o   o
a   b  c  d    g   h  k   m   n r  f o   o
a   b  c  d    g   h  l   m   n q  f o   o
a   b  c  d    g   h  l   m   n w  f o   o
a   b  c  d    g   h  l   m   n e  f o   o
a   b  c  d    g   h  l   m   n r  f o   o
a   b  c  e    g   h  i   m   n q  f o   o
a   b  c  e    g   h  i   m   n w  f o   o
a   b  c  e    g   h  i   m   n e  f o   o
a   b  c  e    g   h  i   m   n r  f o   o
a   b  c  e    g   h  j   m   n q  f o   o
a   b  c  e    g   h  j   m   n w  f o   o
a   b  c  e    g   h  j   m   n e  f o   o
a   b  c  e    g   h  j   m   n r  f o   o
a   b  c  e    g   h  k   m   n q  f o   o
a   b  c  e    g   h  k   m   n w  f o   o
a   b  c  e    g   h  k   m   n e  f o   o
a   b  c  e    g   h  k   m   n r  f o   o
a   b  c  e    g   h  l   m   n q  f o   o
a   b  c  e    g   h  l   m   n w  f o   o
a   b  c  e    g   h  l   m   n e  f o   o
a   b  c  e    g   h  l   m   n r  f o   o
a   b  c  f    g   h  i   m   n q  f o   o
a   b  c  f    g   h  i   m   n w  f o   o
a   b  c  f    g   h  i   m   n e  f o   o
a   b  c  f    g   h  i   m   n r  f o   o
a   b  c  f    g   h  j   m   n q  f o   o
a   b  c  f    g   h  j   m   n w  f o   o
a   b  c  f    g   h  j   m   n e  f o   o
a   b  c  f    g   h  j   m   n r  f o   o
a   b  c  f    g   h  k   m   n q  f o   o
a   b  c  f    g   h  k   m   n w  f o   o
a   b  c  f    g   h  k   m   n e  f o   o
a   b  c  f    g   h  k   m   n r  f o   o
a   b  c  f    g   h  l   m   n q  f o   o
a   b  c  f    g   h  l   m   n w  f o   o
a   b  c  f    g   h  l   m   n e  f o   o
a   b  c  f    g   h  l   m   n r  f o   o
3
додано
Мені шкода, моя заява була трохи тупою. Я просто мав на увазі, що ваш код не буде працювати з усіма можливими рядками: наприклад, якщо ви запустите свій код за допомогою line = 'a {} bcd, e, fghi, j, k, lm n' , то ви отримаєте IndexError: індекс кортежу за межами діапазону . Загалом я вважаю, що будь-який рядок, прочитаний із файлу, є небезпечним, і я не розглядаю небезпечні рядки як шаблони форматування, коли-небудь. Ви можете, звичайно, вийти зі строки спочатку, а потім вимкнути його після форматування, але тоді ваш код буде набагато складнішим, ніж він має бути. Ось чому я віддаю перевагу моїй відповіді.
додано Автор MiniQuark, джерело
Я думаю, ви маєте рацію, але це схильні до помилок. Чесно кажучи, я віддаю перевагу моїй відповіді. :-) Я відредагував його, щоб дозволити зберегти оригінальний інтервал.
додано Автор MiniQuark, джерело
Ось, це може бути трохи небезпечним, залежно від виду даних. Що робити, якщо дані містять де-небудь код {} ? Якщо дуже важливо зберегти оригінальний інтервал, я б зробив це іншим способом.
додано Автор MiniQuark, джерело
Краще, ніж моє, оскільки воно зберігає пробіл між предметами.
додано Автор glglgl, джерело
@MiniQuark Як схильна помилка? Він чудово працює.
додано Автор Ashwini Chaudhary, джерело
@MiniQuark Якщо дані містять де-які дані {} , ми можемо втекти від них за допомогою {{}} .
додано Автор Ashwini Chaudhary, джерело

Більшість інших відповідей виготовляють лише одну лінію, а не кілька рядків, які вам, здається, потрібні.

Щоб досягти бажаного, ви можете працювати кількома способами.

Рекурсивне рішення здається найбільш інтуїтивно зрозумілим для мене:

def dothestuff(l):
    for n, i in enumerate(l):
        if ',' in i:
            # found a "," entry
            items = i.split(',')
            for j in items:
                for rest in dothestuff(l[n+1:]):
                    yield l[:n] + [j] + rest
            return
    yield l


line = "a   b  c  d,e,f    g   h  i,j,k,l   m   n"
for i in dothestuff(line.split()): print i
1
додано

Якщо я правильно зрозумів ваш приклад, то вам потрібно наступне

import itertools
sss = "a   b  c  d,e,f    g   h  i,j,k,l   m   n  d,e,f "
coma_separated = [i for i in sss.split() if ',' in i]
spited_coma_separated = [i.split(',') for i in coma_separated]
symbols = (i for i in itertools.product(*spited_coma_separated)) 
                     #use generator statement to save memory
for s in symbols:
    st = sss
    for part, symb in zip(coma_separated, s):
        st = st.replace(part, symb, 1) # To prevent replacement of the 
                                       # same coma separated group replace once 
                                       # for first occurance
    print (st.split()) # for python3 compatibility
1
додано
@ Максим, фіксований
додано Автор oleg, джерело
вибачте неправильну назву змінної. слід виправити
додано Автор oleg, джерело
Здається складним, але це працює. Ви можете зробити це для Python3?
додано Автор Maxime Chéramy, джерело
for i in range(len(line)-1):
    if line[i] == ',':
        line = line.replace(line[i]+line[i+1], '')
0
додано
for i in range(len(line)-1):
    if line[i] == ',':
        line = line.replace(line[i]+line[i+1], '')
0
додано
import itertools
line_data = 'a   b  c  d,e,f    g   h  i,j,k,l   m   n'
comma_fields_indices = [i for i,val in enumerate(line_data.split()) if "," in val]
comma_fields = [i.split(",") for i in line_data.split() if "," in i]
all_comb = []
for val in itertools.product(*comma_fields):
    sline_data = line_data.split()
    for index,word in enumerate(val):
        sline_data[comma_fields_indices[index]] = word
    all_comb.append(" ".join(sline_data))
print all_comb
0
додано
Ви, ймовірно, хочете "". Join (sline_data) замість ",". Join (sline_data)
додано Автор MiniQuark, джерело
Що таке використання підрахунку?
додано Автор Maxime Chéramy, джерело
@MiniQuark: Хм, да, дякую
додано Автор Nakamura, джерело
@ Максим Хм, так, немає потреби в підрахунку. знову дякую :)
додано Автор Nakamura, джерело
ІТ КПІ - Python
ІТ КПІ - Python
625 учасників

Канал обговорень про всякі штуки зі світу пайтону. Прохання: 0. мати повагу одне до одного; 1. не матюкатися в сторону людей; 2. не захламляти тред повідомленнями по одному слову;