2016-04-17 37 views
2

として、私は単語のリストの形で文章を持って、例えば正規表現の入力

は今、私は条件節['if', 'it', 'will', 'rain']を見つけるしたいと思います。原則として、文から文字列を作成することができます。 s = ' '.join(sentence)は、Iおよび正規表現を使用して:正規表現を判断する

p = re.compile(r'(\bif\b[a-zA-z0-9\'\s]+)\s*(,*)\s*(then|,)') 
for m in p.finditer(s): 
    print m.start(1), m.end(1), '['+s[ m.start(1) : m.end(1) ]+']' 

必要はありません、それだけですぐに:)にスケッチしています。これは私に出力を与える:0 16 [if it will rain ]

これまでのところとても良い。しかし、今私は、私のorignalリストへの接続が見当たりません。正規表現は私に文字の位置を与え、単語/トークンの位置は与えません。理想的には、私は0と3を得るので、条件節がsentence[0:3]であることが分かります。私は、文字の位置を対応するリストインデックスにマップするメソッドを書くことができると確信していますが、すべてこれを行う方が良いと確信しています。

もちろん、正規表現を無視して、リストをループして、適切な開始条件と終了条件を考え出すことができます。しかし、現在のレギュラーは、要求された条件を明示的にするために「隠す」ため、現在はむしろきれいに見える。彼らはまた、例えば、条件節が他の単語やフレーズによって示される場合を簡略化:

sentence = ['as', 'long', 'as', 'it', 'will', 'rain', ',', 'I', 'will', 'stay', 'at', 'home'] 

簡単ループを用いたもう少し迷惑な、正規表現でこれを反映するために、私が想定しています。

EDIT:非常に簡単な解決策は、実際にそこにないことを見て、私は正規表現と元の単語リストの文字列としての文との間のマッピングを作成するための私の考えを先に行ってきました:

def join(self, word_list, separator=' '): 
    mapping = [] 
    string = separator.join(word_list) 
    for idx, word in enumerate(word_list): 
    for character in word: 
     mapping.append(idx) 
    for character in separator: 
     mapping.append(idx) 
    return string, mapping 

で、私の入力にstring, mapping = join(sentence)結果をこの方法を適用する:正規表現がマッチの範囲として私016を与えた場合、

mapping = [0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9] 

今、私は元sentenceリーにインデックスを調べることができますstはmapping[0] = 0と​​です。これまでのところ、これはかなりうまくいくようです。そして、私は試合をするために、文字列の正規表現を使用するので、私は簡単に条件節の代替製剤をサポートすることができ、例えば:

再び
CONDITIONAL_PHRASES = ['if', 'as long as', 'even if'] 
... 
p = re.compile(r"((%s)\s+[a-zA-z0-9'\s]+)\s*(then|,)" % '|'.join(CONDITIONAL_PHRASES)) 

、私は正規表現はすでに完璧であることを言っていないんだけど、それはサポートしています条件文のための異なるインジケータワードを含む複数のセンテンス。

+1

あなたはどこまで行きたいのかによって異なりますが、あなたはパーサー領域の途中にあります。したがって、パーサーベースのソリューションに切り替えると、より強固な基盤が得られる可能性があります。 – mkiever

+2

私はPythonを話しません;)しかし、速いgoogleは、 'sentence.index( '、')'を実行する方が良いのではないかと思うし、 'sentence.index( 'then')' 。そうでなければ、 'cond_end_idx =(iの場合はi、itemは列挙する項目が一致すれば '(then |、)'、item))' – ClasG

+0

は 'if'あなたの 'sentence'に'、 'または' then'? – rock321987

答えて

1

注: -if,またはthenの唯一の発生がsentence

であった場合、私はあなたができる1つの以上のキャプチャグループを含めるように正規表現

re.compile("((\\bif\\b)[a-zA-z0-9\\'\\s]+)\\s*(,*)\\s*(then|,)") 

を少し変更しましたこれにはre.findallを使用してください。

arr = re.findall(p, s) 

arr[0][1]最初のキャプチャグループ(ストリングif)を含み、arr[0][3]は、第三の捕捉群(文字列then又は,)を含みます。あなたが使用して文字列を形成することができ、今、これら2として

start = sentence.index(arr[0][1]) 
end = sentence.index(arr[0][3]) 

のインデックスを見つけるためにインデックスを使用することができます

stri = ' '.join(sentence[start: end]) 

注1: -ifの複数のオカレンスがある場合と、 ,またはsentencethenは(重複しない)、あなたはすべてのタプルを反復処理する必要があります

arr = re.findall(p, s) 
pos = 0 #It stores the last occurrence of matched group 
for i, x in enumerate(arr): 
    start = sentence.index(x[1], pos) 
    end = sentence.index(x[3], pos) 
    stri = ' '.join(sentence[start: end]) 
    print(stri) 
    pos = sentence.index(x[3], pos) + 1 

Ideone Demo

注2: -は、文字列が見つからない場合indexは例外を発生させることに留意してください。同期それらを保つ - あなたはまた、文字列にしてから、あなたの入力を切り替える必要があるために、定期的な表現からの切り替え

+0

ロック、ありがとう! "if"の方がかなりいいようですが、 'sentence = ['as'、 'long'、 'as'、 'it'、 'will'、...]'のように動作しないようです条件節は単一の語ではなく語句によって示される。したがって、単純な索引参照は失敗します。 – Christian

+0

@Christianよく私は英語ではあまりよくありません。あなたはそれがどのように動作すべきかを示すために例を挙げることができます。また、あなたが働かせる可能性のあるケースを教えてください。 – rock321987

+0

私のオリジナルの質問を編集してください。元の例 'sentence = ['if'、 'it'、 'will'、...]'条件付き文字の開始と終了を反映する値で '[0、4]'を得たいとします句。 'sentence = ['as'、 'long'、 'as'、 'it'、 'will'、...]'結果は '[0、6]'でなければなりません。 "if"の代わりに "as long"を指定すると、現在のメソッドが正しく動作しなくなります。 – Christian

1

上で実行する前に、それを処理することは、それは問題のあるものにします。これは、一度に「文」に対して「フレーズ」、一つの単語を比較し、そこにあれば[]を返し

sentence = ['if', 'it', 'will', 'rain', ',', 'I', 'will', 'stay', 'at', 'home'] 
phrase = ['if', [',', 'then']] 

def findPhrase(phrase, full): 
    currentpos = 0 
    isFirst = True 
    result = [] 
    for part in phrase: 
    if isinstance(part, list): 
     partOffset = 999 
     for subpart in part: 
     if subpart in full[currentpos:]: 
      if full[currentpos:].index(subpart) < partOffset: 
      partOffset = full[currentpos:].index(subpart) 
     if partOffset == 999: 
     return [] 
     currentpos += partOffset 
     if isFirst: 
     result.append (currentpos) 
     else: 
     result[-1] = currentpos 
     continue 
    if not part in full[currentpos:]: 
     return [] 
    currentpos = currentpos + full[currentpos:].index(part) 
    if isFirst: 
     result.append (currentpos) 
    else: 
     result[-1] = currentpos 
    # check for a single word match; should still return a range 
    # .. just duplicate last item 
    if len(result) == 1: 
     result.append(result[0]) 
    return result 

res = findPhrase (phrase, sentence) 
if res == []: 
    print 'not found' 
else: 
    print res 
    print sentence[res[0]:res[1]+1] 

:どのようにORのようなものを持っているリスト比較機能について

一致しない場合はstart:endの範囲があります。

これの出力は

[0, 4] 
['if', 'it', 'will', 'rain', ','] 

このような「オプション」と「どの試合」などの項目でfindPhrase機能を拡張することが可能であるが、その後、あなたは単純な配列ベースの構文を拡張する必要があると思いますです辞書のようなものに。

現在、コードは、間に何かを無視して、1つの見つかった単語から次へとスキップします。あなたは「言葉の任意の数をスキップ」を意味する、明示的な'*'「フレーズ」アイテムを追加したい場合は、それは試合の句に最後アイテムだ場合、あなたは((1)の試験に必要そうならば、あなたは最後の項目を発することができますsentenceの)、及び/又は(2)phrase項目がsentenceに存在するかどうかを確認するために別の先読みのような機能を実現します。 (これは、正規表現パーサーを模倣するのに非常に近いものです。)

+2

うわー!それはとても簡単なのですか? :/それはうまくいくかもしれませんが、私は* simple *という単語を取り出します。あなたの機能は31行です。 – zondo

+0

@ zondo:point taken :)ますます多くの機能を追加すると、私は迷ってしまいました。しかし、一般的なアイデアは明確でなければなりません。私はリスト内包やそのようなもので関数を短縮することに失敗しました - あなたは方法を見ますか? – usr2564301

+2

'if部分チェック 'の' if'チェックは '-1!= full [currentpos] .find(subpart) zondo

関連する問題