2011-08-10 14 views
7

これは、この質問に対するフォローアップと複雑さです。Extracting contents of a string within parentheses。私は次の文字列を持っていたその質問には 正規表現を使用して文字列から情報を抽出する

- 私は、問題を一般化するため

[('Will Farrell', 'Nick Hasley'), ('Rebecca Hall', 'Samantha')] 

-

"Will Farrell (Nick Hasley), Rebecca Hall (Samantha)" 

そして私は(actor, character)の形でタプルのリストを取得したいですやや複雑な文字列で、同じ情報を抽出する必要があります。

[('Will Farrell', 'Nick Hasley'), ('Rebecca Hall', 'Samantha'), ('Glenn Howerton', 'Gary'), 
('Stephen Root',''), ('Lauren Dern', 'Delilah')] 

私はフィラーの言葉(と、そして、&、など)を置き換えることができます知っているが、次のことができます。私は次のようにこれをフォーマットする必要が

"Will Ferrell (Nick Halsey), Rebecca Hall (Samantha), Glenn Howerton (Gary), 
with Stephen Root and Laura Dern (Delilah)" 

- 私が持っている文字列があります空白のエントリを追加する方法を理解していない - '' - アクターの文字名がない場合(この場合はStephen Root)これを行う最善の方法は何でしょうか?

最後に、アクターに複数のロールがある場合は考慮する必要があり、アクターが持つ各ロールに対してタプルを作成する必要があります。私が持っている最後の文字列は次のとおりです。

"Will Ferrell (Nick Halsey), Rebecca Hall (Samantha), Glenn Howerton (Gary, Brad), with 
Stephen Root and Laura Dern (Delilah, Stacy)" 

そして、私は次のようにタプルのリストを構築する必要があります:

[('Will Farrell', 'Nick Hasley'), ('Rebecca Hall', 'Samantha'), ('Glenn Howerton', 'Gary'),  
('Glenn Howerton', 'Brad'), ('Stephen Root',''), ('Lauren Dern', 'Delilah'), ('Lauren Dern', 'Stacy')] 

ありがとうございました。

+0

@Michaelでgroups('')を使用することです:スペルの編集をありがとうございました。 – David542

+0

正規表現を使用するのは本当に必要ですか? – utdemir

+0

いいえ、それは何でもかまいません。どんな作品でも最高です。 – David542

答えて

4
import re 
credits = """Will Ferrell (Nick Halsey), Rebecca Hall (Samantha), Glenn Howerton (Gary, Brad), with 
Stephen Root and Laura Dern (Delilah, Stacy)""" 

# split on commas (only if outside of parentheses), "with" or "and" 
splitre = re.compile(r"\s*(?:,(?![^()]*\))|\bwith\b|\band\b)\s*") 

# match the part before the parentheses (1) and what's inside the parens (2) 
# (only if parentheses are present) 
matchre = re.compile(r"([^(]*)(?:\(([^)]*)\))?") 

# split the parts inside the parentheses on commas 
splitparts = re.compile(r"\s*,\s*") 

characters = splitre.split(credits) 
pairs = [] 
for character in characters: 
    if character: 
     match = matchre.match(character) 
     if match: 
      actor = match.group(1).strip() 
      if match.group(2): 
       parts = splitparts.split(match.group(2)) 
       for part in parts: 
        pairs.append((actor, part)) 
      else: 
       pairs.append((actor, "")) 

print(pairs) 

出力:

[('Will Ferrell', 'Nick Halsey'), ('Rebecca Hall', 'Samantha'), 
('Glenn Howerton', 'Gary'), ('Glenn Howerton', 'Brad'), ('Stephen Root', ''), 
('Laura Dern', 'Delilah'), ('Laura Dern', 'Stacy')] 
0

何が欲しいの大文字で始まる単語のシーケンスに加え、いくつかの合併症を(私見あなたはそれぞれの名前が名前姓で作られていると仮定することはできませんが、また、姓を名識別していますジュニア・クロード・バン・ダンメ、ルイ・ダ・シルヴァなど)の名前を付け加えることができます。

これは、あなたが投稿したサンプル入力の過度の可能性がありますが、私が上に書いたように、私はすぐに物事が乱雑になると思うので、私はnltkを使ってこれに取り組んでいます。

ここでは非常によく、テストは非常に原油とないスニペットのですが、それは仕事をする必要があります:あなたは

import nltk 
from nltk.chunk.regexp import RegexpParser 

_patterns = [ 
    (r'^[A-Z][a-zA-Z]*[A-Z]?[a-zA-Z]+.?$', 'NNP'), # proper nouns 
    (r'^[(]$', 'O'), 
    (r'[,]', 'COMMA'), 
    (r'^[)]$', 'C'), 
    (r'.+', 'NN')         # nouns (default) 
] 

_grammar = """ 
     NAME: {<NNP> <COMMA> <NNP>} 
     NAME: {<NNP>+} 
     ROLE: {<O> <NAME>+ <C>} 
     """  
text = "Will Ferrell (Nick Halsey), Rebecca Hall (Samantha), Glenn Howerton (Gary, Brad), with Stephen Root and Laura Dern (Delilah, Stacy)" 
tagger = nltk.RegexpTagger(_patterns)  
chunker = RegexpParser(_grammar) 
text = text.replace('(', '(').replace(')', ')').replace(',', ' , ') 
tokens = text.split() 
tagged_text = tagger.tag(tokens) 
tree = chunker.parse(tagged_text) 

for n in tree: 
    if isinstance(n, nltk.tree.Tree) and n.node in ['ROLE', 'NAME']: 
     print n 

# output is: 
# (NAME Will/NNP Ferrell/NNP) 
# (ROLE (/O (NAME Nick/NNP Halsey/NNP))/C) 
# (NAME Rebecca/NNP Hall/NNP) 
# (ROLE (/O (NAME Samantha/NNP))/C) 
# (NAME Glenn/NNP Howerton/NNP) 
# (ROLE (/O (NAME Gary/NNP ,/COMMA Brad/NNP))/C) 
# (NAME Stephen/NNP Root/NNP) 
# (NAME Laura/NNP Dern/NNP) 
# (ROLE (/O (NAME Delilah/NNP ,/COMMA Stacy/NNP))/C) 

あなたはその後、タグ付けされた出力を処理し、代わりに印刷のリストに名前と役割を置く必要がありますが、その絵を入手する。

ここでは、_patternsの正規表現に従って各トークンにタグを付け、単純な文法に従って複雑なチャンクを作成するために2回目のパスを実行する最初のパスを行います。あなたは文法とパターンをあなたが望むように複雑にすることができます。名前のばらつき、面倒な入力、略語などをキャッチします。

私はこれを、正規表現の1つのパスで行うことは、重要ではない入力に対する痛みになると思います。

それ以外の場合、Tim's solutionは、投稿した入力とnltkの依存関係がうまく問題を解決していません。あなたが非正規表現のソリューションをしたい場合は

0

...(。ネストされた括弧を前提としていない)

in_string = "Will Ferrell (Nick Halsey), Rebecca Hall (Samantha), Glenn Howerton (Gary, Brad), with Stephen Root and Laura Dern (Delilah, Stacy)"  

in_list = [] 
is_in_paren = False 
item = {} 
next_string = '' 

index = 0 
while index < len(in_string): 
    char = in_string[index] 

    if in_string[index:].startswith(' and') and not is_in_paren: 
     actor = next_string 
     if actor.startswith(' with '): 
      actor = actor[6:] 
     item['actor'] = actor 
     in_list.append(item) 
     item = {} 
     next_string = '' 
     index += 4  
    elif char == '(': 
     is_in_paren = True 
     item['actor'] = next_string 
     next_string = ''  
    elif char == ')': 
     is_in_paren = False 
     item['part'] = next_string 
     in_list.append(item) 
     item = {}     
     next_string = '' 
    elif char == ',': 
     if is_in_paren: 
      item['part'] = next_string 
      next_string = '' 
      in_list.append(item) 
      item = item.copy() 
      item.pop('part')     
    else: 
     next_string = "%s%s" % (next_string, char) 

    index += 1 


out_list = [] 
for dict in in_list: 
    actor = dict.get('actor') 
    part = dict.get('part') 

    if part is None: 
     part = '' 

    out_list.append((actor.strip(), part.strip())) 

print out_list 

出力: [( 'ウィルフェレル'、 'ニックハルシー')、( 'レベッカ・ホールグレン・ハワードン、ブラッド、スティーブン・ルート、ローラー・ダーン、デリラ、 (「ローラ・ダーン」、「ステイシー」)]

1

ティムPietzckerの溶液は、(パターンがあまりにも変更されていることに注意)に簡略化することができる。

import re 
credits = """ Will Ferrell (Nick Halsey), Rebecca Hall (Samantha), Glenn Howerton (Gary, Brad), with 
Stephen Root and Laura Dern (Delilah, Stacy)""" 

# split on commas (only if outside of parentheses), "with" or "and" 
splitre = re.compile(r"(?:,(?![^()]*\))(?:\s*with)*|\bwith\b|\band\b)\s*") 

# match the part before the parentheses (1) and what's inside the parens (2) 
# (only if parentheses are present) 
matchre = re.compile(r"\s*([^(]*)(?<!)\s*(?:\(([^)]*)\))?") 

# split the parts inside the parentheses on commas 
splitparts = re.compile(r"\s*,\s*") 

pairs = [] 
for character in splitre.split(credits): 
    gr = matchre.match(character).groups('') 
    for part in splitparts.split(gr[1]): 
     pairs.append((gr[0], part)) 

print(pairs) 

その後:

import re 
credits = """ Will Ferrell (Nick Halsey), Rebecca Hall (Samantha), Glenn Howerton (Gary, Brad), with 
Stephen Root and Laura Dern (Delilah, Stacy)""" 

# split on commas (only if outside of parentheses), "with" or "and" 
splitre = re.compile(r"(?:,(?![^()]*\))(?:\s*with)*|\bwith\b|\band\b)\s*") 

# match the part before the parentheses (1) and what's inside the parens (2) 
# (only if parentheses are present) 
matchre = re.compile(r"\s*([^(]*)(?<!)\s*(?:\(([^)]*)\))?") 

# split the parts inside the parentheses on commas 
splitparts = re.compile(r"\s*,\s*") 

gen = (matchre.match(character).groups('') for character in splitre.split(credits)) 

pp = [ (gr[0], part) for gr in gen for part in splitparts.split(gr[1])] 

print pp 

トリックは、引数''

関連する問題