【问题标题】:nested dictionaries and regex for sorting a play into lines of dialogue嵌套字典和正则表达式,用于将剧本分类为对话行
【发布时间】:2018-07-18 04:45:19
【问题描述】:

我正在使用 Python 3.6.3 获取 TV/Play/whatever 脚本并将其分类到字典中,该字典将字符及其对话行配对。

我已经能够得到我想要的结果,它为每个 Character: 嵌套了 {Line#:Line} 对,但我想知道是否有更有效的方法来达到这一点。特别是我最初拆分文本的方式,我首先获取对话中各个单词的列表,然后通过遍历字典的副本来加入这些列表。

import re

text = """
Steve: Is that his chart? 
Phil: Yes. 
Steve: Mm-hmm. I'll see him in a few moments. 
Phil: All right. Thank you, Doctor. 
P.A.: Dr. Braun, Dr. Miller, and Dr. Sullivan, emergency. 
Steve: How is she, Jessie? 
Jessie: Still fighting everybody and everything. She wants to live in the 
dark and never see her face again. That's about what she was doing when I went 
in. She had the blinds all drawn, towel over the mirror. """
## general hospital!    

dialog = {}
count = 0
cast = []
for word in text.split():
    if re.match(".*\:", word):
        character = word[:-1]
        count += 1      
        if character not in dialog:
            cast.append(character)
            dialog[character] = {}
            dialog[character][count] = []
        else:
            dialog[character][count] = []
    else:
        dialog[character][count].append(word)


fullLines = {}
for k,v in dialog.items(): 
    fullLines[k] = {}
    for k1,v1 in v.items():
        v1 = ' '.join(v1)
        fullLines[k][k1] = v1

有没有一种方法可以使用正则表达式拆分文本以识别对话提示 - “字符:”并用它拆分文本?我试着放置 re.compile(r".*\:") 变成 split() 就像这样

match = re.compile(".*\:")
for word in text.split(match): 

并得到错误TypeError: must be str or None, not _sre.SRE_Pattern。所以我基本上明白为什么这不起作用。我还在学习python,所以还在积累方法和pythonic的习惯。

【问题讨论】:

  • 你想要的输出是什么?
  • 这是我目前得到的:
  • ` {'Steve': {1: '这是他的图表吗?', 3: "嗯-嗯。我一会儿见他。", 6: '她怎么样, Jessie?'}, 'Phil': {2: 'Yes.', 4: '好吧。谢谢你,博士。'},'P.A.':{5:'博士。布劳恩、米勒博士和沙利文博士,紧急情况。'},“杰西”:{7:“仍在与每个人和所有事情作斗争。她想生活在黑暗中,再也见不到她的脸。这就是她正在做的事情当我进去的时候。她把百叶窗都拉上了,毛巾盖在镜子上。”}}`
  • 这是我的目标,但我想知道我是否以一种过于复杂的方式到达那里。

标签: python regex dictionary


【解决方案1】:

你可以使用下面的表达式

^                             # start of the line
(?P<actor>[A-Z][^:\n\r]+):\s* # a potential actor
(?P<text>[\s\S]+?)            # the following text
(?=^[A-Z]|\Z)                 # lookaheads for the text

结合嵌套的defaultdict 作为容器。剩下的唯一事情是通过计算换行符到该点来计算行号(由match 对象定义)。

查看regex101.com 上的表达式演示。


Python 中,这可能是:
import re
from collections import defaultdict

string = """Steve: Is that his chart? 
Phil: Yes. 
Steve: Mm-hmm. I'll see him in a few moments. 
Phil: All right. Thank you, Doctor. 
P.A.: Dr. Braun, Dr. Miller, and Dr. Sullivan, emergency. 
Steve: How is she, Jessie? 
Jessie: Still fighting everybody and everything. She wants to live in the 
dark and never see her face again. That's about what she was doing when I went 
in. She had the blinds all drawn, towel over the mirror."""

rx = re.compile(r'''
    ^
    (?P<actor>[A-Z][^:\n\r]+):\s*
    (?P<text>[\s\S]+?)
    (?=^[A-Z]|\Z)
    ''', re.MULTILINE | re.VERBOSE)

# create the nested defaultdict
result = defaultdict(lambda : defaultdict(int))

for m in rx.finditer(string):
    start = m.start()
    line = string.count('\n', 0, start) + 1
    result[m.group('actor')][line] = m.group('text').strip()

print(result)

这会产生

defaultdict(<function <lambda> at 0x10ffe0e18>, {'Steve': defaultdict(<class 'int'>, {1: 'Is that his chart?', 3: "Mm-hmm. I'll see him in a few moments.", 6: 'How is she, Jessie?'}), 'Phil': defaultdict(<class 'int'>, {2: 'Yes.', 4: 'All right. Thank you, Doctor.'}), 'P.A.': defaultdict(<class 'int'>, {5: 'Dr. Braun, Dr. Miller, and Dr. Sullivan, emergency.'}), 'Jessie': defaultdict(<class 'int'>, {7: "Still fighting everybody and everything. She wants to live in the \ndark and never see her face again. That's about what she was doing when I went \nin. She had the blinds all drawn, towel over the mirror."})})

【讨论】:

  • 谢谢。特别是对于链接/演示。我正在尝试练习正则表达式,它正在慢慢下沉。命名捕获组的概念真的很方便。有许多概念和方法,例如 start() 和 finditer()。很多有用的东西要跟进......
【解决方案2】:

你可以使用正则表达式和itertools.groupby:

import re
import itertools
text = """
Steve: Is that his chart? 
Phil: Yes. 
Steve: Mm-hmm. I'll see him in a few moments. 
Phil: All right. Thank you, Doctor. 
P.A.: Dr. Braun, Dr. Miller, and Dr. Sullivan, emergency. 
Steve: How is she, Jessie? 
Jessie: Still fighting everybody and everything. She wants to live in the dark and never see her face again. That's about what she was doing when I went in. She had the blinds all drawn, towel over the mirror. """
parts = [[a, i, b] for i, [a, b] in enumerate([re.split(':\s*', i) for i in filter(None, text.split('\n'))], start = 1)]
final_parts = {a:dict([i[1:] for i in b]) for a, b in itertools.groupby(sorted(parts, key=lambda x:x[0]), key=lambda x:x[0])}

输出:

{'Steve': {1: 'Is that his chart? ', 3: "Mm-hmm. I'll see him in a few moments. ", 6: 'How is she, Jessie? '}, 'Jessie': {7: "Still fighting everybody and everything. She wants to live in the dark and never see her face again. That's about what she was doing when I went in. She had the blinds all drawn, towel over the mirror. "}, 'Phil': {2: 'Yes. ', 4: 'All right. Thank you, Doctor. '}, 'P.A.': {5: 'Dr. Braun, Dr. Miller, and Dr. Sullivan, emergency. '}}

【讨论】:

  • 谢谢!您的解决方案非常简洁,并为我提供了很多学习机会。我不确定的一个组件是text.split('\n') 这是否需要格式化脚本以使字符行没有中断?
  • @AyO 多行字符串固有地包含 \n 字符,因此除非您从文件、数据库等读取数据,否则您不需要预先格式化文本。
猜你喜欢
  • 2021-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-24
  • 2013-04-14
  • 1970-01-01
相关资源
最近更新 更多