【问题标题】:Parsing A Screenplay解析剧本
【发布时间】:2021-03-05 20:47:55
【问题描述】:

您好,我正在尝试解析剧本并尝试使用正则表达式捕获 (NAME) : (Dialogue)。到目前为止,在正则表达式 101 上,我有 re.complie('(\w+)\n(.*)'),但正如您在图像中看到的那样,对于某些包含特殊字符的行,它会变得平坦。任何帮助表示赞赏。 (添加文本格式以帮助重现性)

                 CLAIRE
      Morning, beauty.

Caitlin lets out a grunt and rolls over onto her belly.

                 CLAIRE
      Let's go.  Or we'll never leave on time.

From out of the pillow comes Caitlin's voice.

                 CAITLIN
           (muffled)
      I'm totally ready.

Claire glances around at the piles of unpacked clothes.

                 CLAIRE
      Come on, I'll make you some waffles,
      maybe we'll squeeze in a trip to the
      mall.
           (beat)
      Caitlin...

【问题讨论】:

  • 您没有解释您期望的输出。 (?m)^\s*\b([A-Z]+)\b\s*\n(.*(?:\n.+)*) 对你有用吗?见the regex demo
  • 谢谢,@WiktorStribiżew,它完美地捕捉到了第一组中的名称和第二组中的所有对话。我想要的输出是一个字典,其中键是第一组,值是第二组。我在 OP 中使用了该模式并编写了代码来执行此操作。现在有了你的模式,非常感谢。我会发布完整的答案,以防其他有需要的人偶然发现它。

标签: python regex parsing


【解决方案1】:

你可以使用

(?m)^\s*\b([A-Z]+)\b\s*\n(.*(?:\n.+)*)

请参阅regex demo

详情

  • (?m)^ - 行首((?m)re.M 选项相同)
  • \s* - 零个或多个空格
  • \b([A-Z]+)\b - 第 1 组:一个大写的整个单词(\b 是单词边界)
  • \s*
  • \n - 换行符
  • (.*(?:\n.+)*) - 第 2 组:一行的其余部分,然后是零个或多个换行符序列,然后是该行的其余部分(因此,直到第一个空白行的任何文本)。

Python demo

import re
rx = r"^\s*\b([A-Z]+)\b\s*\n(.*(?:\n.+)*)"
text = "                 CLAIRE\n      Morning, beauty.\n\nCaitlin lets out a grunt and rolls over onto her belly.\n\n                 CLAIRE\n      Let's go.  Or we'll never leave on time.\n\nFrom out of the pillow comes Caitlin's voice.\n\n                 CAITLIN\n           (muffled)\n      I'm totally ready.\n\nClaire glances around at the piles of unpacked clothes.\n\n                 CLAIRE\n      Come on, I'll make you some waffles,\n      maybe we'll squeeze in a trip to the\n      mall.\n           (beat)\n      Caitlin..."
print( re.findall(rx, text, re.M) )

输出:

[
  ('CLAIRE', '      Morning, beauty.'),
  ('CLAIRE', "      Let's go.  Or we'll never leave on time."),
  ('CAITLIN', "           (muffled)\n      I'm totally ready."),
  ('CLAIRE', "      Come on, I'll make you some waffles,\n      maybe we'll squeeze in a trip to the\n      mall.\n           (beat)\n      Caitlin...")
]

【讨论】:

    【解决方案2】:

    我马上看到的一些问题:

    • 您没有利用角色名称全部大写的事实。为此,请在您的正则表达式中使用 [A-Z]+ 而不是 \w+
    • 您没有使用 SingleLine 正则表达式选项,所以这会阻止 . 匹配多行。

    【讨论】:

    • 是的,我已经 [A-Z]+ 就位了(现在仍在修补它)我将研究一下我以前从未听说过该术语的 SingleLine 正则表达式选项。感谢您的洞察力。
    【解决方案3】:

    感谢@Wiktor Stribiżew 的模式,获得所需结果的完整代码。

    # Grouped regex pattern to capture char and dialouge in a tuple
    char_dialogue = re.compile(r"(?m)^\s*\b([A-Z]+)\b\s*\n(.*(?:\n.+)*)")
    extract_dialogue = char_dialogue.findall(script)
    
    final_dict = {}
    
    for element in extract_dialogue:
       # Seperating the character and dialogue from the tuple
       char = element[0]
       line = element[1]
       # If the char is already a key in the dictionary
       # and line is not empty append the dialogue to the value list
       if char in final_dict:
           if line != '':
               final_dict[char].append(line)
       else:
           # Else add the character name to the dictionary keys with their first line
           # Drop any lower case matches from group 0
           # Can adjust the len here if you have characters with fewer letters
           if char.isupper() and len(char) >2:
               final_dict[char] = [line]
    
            
    # Some final cleaning to drop empty dalouge 
    
    final_dict = {k: v for k, v in final_dict.items() if v  != ['']}
    
    # More filtering to reutrn only main characters with more than 50 
    # lines of dialogue 
    
    final_dict = {k: v for k, v in final_dict.items() if len(v) > 50}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-13
      • 1970-01-01
      • 2021-12-01
      • 1970-01-01
      • 2018-09-21
      • 2020-05-08
      相关资源
      最近更新 更多