2010-11-10 4 views
1

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

[категория] Ужасы:

  1. фильм
  2. фильм
  3. Фильм

[категория] Комедия:

  1. Фильм

[категория] Действие:

  1. фильм
  2. фильм

Как создать функцию, которая извлекает и упаковывает все названия фильмов ниже определенного [категории] * в массив, не переливаясь в другую категорию?

+0

Можете ли вы повторно разметить пример текстового файла как моноширинный «код»? Пронумерованные списки затрудняют просмотр точной последовательности символов. –

+0

@Renzor - Пожалуйста, представьте пример короткого кода, как эта функция должна быть вызвана и что вы ожидаете получить в ответ, например. 'myFavorite (Horror) возвращает [Movie, Movie, Movie]' – Theodor

ответ

1

Используйте negative lookahead:

\[category\](?:(?!\[category\]).)* 

будет соответствовать одной целой категории (если регулярное выражение компилируется с помощью опции re.DOTALL).

Вы можете получить категорию и содержимое отдельно с помощью

\[category\]\s*([^\r\n]*)\r?\n((?:(?!\[category\]).)*) 

После матча mymatch.group(1) будет содержать категорию и mymatch.group(2) будет содержать названия фильмов.

Пример в Python 3.1 (используя строку в качестве mymovies):

>>> import re 
>>> myregex = re.compile(r"\[category\]\s*([^\r\n]*)\r?\n((?:(?!\[category\]).)*)", re.DOTALL) 
>>> for mymatch in myregex.finditer(mymovies): 
...  print("Category: {}".format(mymatch.group(1))) 
...  for movie in mymatch.group(2).split("\n"): 
...   if movie.strip(): 
...    print("contains: {}".format(movie.strip())) 
... 
Category: Horror: 
contains: 1. Movie 
contains: 2. Movie 
contains: 3. Movie 
Category: Comedy: 
contains: 1. Movie 
Category: Action: 
contains: 1. Movie 
contains: 2. Movie 
>>> 
2

Вы можете разобрать файл строка за линией так:

import collections 

result=collections.defaultdict(list) 
with open('data') as f: 
    genre='unknown' 
    for line in f: 
     line=line.strip() 
     if line.startswith('[category]'): 
      genre=line.replace('[category]','',1) 
     elif line: 
      result[genre].append(line) 

for key in result: 
    print('{k} {m}'.format(k=key,m=list(result[key]))) 

дающий

Action: ['1. Movie', '2. Movie'] 
Comedy: ['1. Movie'] 
Horror: ['1. Movie', '2. Movie', '3. Movie'] 
+0

Эй, гораздо приятнее, чем использовать регулярное выражение :) –

+0

Спасибо, @Tim. Ваше регулярное выражение довольно неплотное. Приятно видеть множество решений. – unutbu

2

Уже дано совет другим для вашего текстового формата, я просто вступаю в предложение другого предложения ... Если перезапись файла возможно, простое решение могло бы изменить его ConfigParser -readable (и записи) файла:

 
[Horror] 
1: Movie 
2: Movie 
3: Movie 

[Comedy] 
1: Movie 

[Action] 
1: Movie 
2: Movie 
+0

Хорошее предложение! Ниже приведена ссылка на документацию [ConfigParser documentation] (http://docs.python.org/library/configparser.html) для удобства. –

0
import re 

re_cat = re.compile("\[category\] (.*):") 

categories = {} 

category = None 

for line in open("movies.txt", "r").read().split("\n"): 
    line = line.strip() 
    if not line: 
     continue 
    if re_cat.match(line): 
     category = re_cat.sub("\\1", line) 
     if not category in categories: 
      categories[category] = [] 
continue 
    categories[category].append(line) 

print categories 

делает следующий словарь:

{ 
'Action': ['Movie', 'Movie'], 
'Horror': ['Movie', 'Movie', 'Movie'], 
'Comedy': ['Movie'] 
} 

Мы используем такое же регулярное выражение для сопоставления и удаления названия категории, поэтому эффективно скомпилировать его с помощью re.compile.

У нас есть переменная, действующая category, которая изменяется всякий раз, когда анализируется новая категория. Любая строка, которая не определяет новую категорию, добавляется в словарь categories под соответствующим ключом. Категории, определенные в первый раз, создают список под правильным словарным ключом, но категории также могут быть перечислены несколько раз, и все закончится под правой клавишей.

Любые фильмы, перечисленные перед категорией, будут указаны в словаре под ключом None.