3

Pythonで正規表現を使用して段落から文を抽出しようとしています。
通常、私がテストしているコードは文を正しく抽出しますが、次の段落では文が正しく抽出されません。

段落:

「しかし、マラリア感染症や敗血症の場合、全身の樹状細胞が免疫系に警告することに集中しているため、新たな感染を検出して対応することができなくなります。」新しいタイプのワクチン?

コード:

def splitParagraphIntoSentences(paragraph):

import re

sentenceEnders = re.compile('[.!?][\s]{1,2}(?=[A-Z])')
sentenceList = sentenceEnders.split(paragraph)
return sentenceList
if __name__ == '__main__':
    f = open("bs.txt", 'r')
    text = f.read()
    mylist = []
    sentences = splitParagraphIntoSentences(text)
    for s in sentences:
        mylist.append(s.strip())
        for i in mylist:
            print i

上記の段落でテストすると、入力段落とまったく同じ出力が得られますが、出力は次のようになります-

しかし、マラリア感染症や敗血症の場合、全身の樹状細胞が免疫系に警告することに集中しているため、新たな感染を検出して対応することができなくなります。

新しいタイプのワクチン

正規表現に問題はありますか?

4

3 に答える 3

6

Riccardo Murri の答えは正しいですが、この件についてもう少し詳しく説明したいと思います。

PHP に関して同様の質問がありました: php 文の境界検出。その質問に対する私の答えには、「Mr.」、「Mrs.」などの例外の処理が含まれます。と「ジュニア」。その正規表現を Python で動作するように適合させました (これにより、後読みがより制限されます)。この新しい正規表現を使用するスクリプトの変更およびテスト済みバージョンを次に示します。

def splitParagraphIntoSentences(paragraph):
    import re
    sentenceEnders = re.compile(r"""
        # Split sentences on whitespace between them.
        (?:               # Group for two positive lookbehinds.
          (?<=[.!?])      # Either an end of sentence punct,
        | (?<=[.!?]['"])  # or end of sentence punct and quote.
        )                 # End group of two positive lookbehinds.
        (?<!  Mr\.   )    # Don't end sentence on "Mr."
        (?<!  Mrs\.  )    # Don't end sentence on "Mrs."
        (?<!  Jr\.   )    # Don't end sentence on "Jr."
        (?<!  Dr\.   )    # Don't end sentence on "Dr."
        (?<!  Prof\. )    # Don't end sentence on "Prof."
        (?<!  Sr\.   )    # Don't end sentence on "Sr."
        \s+               # Split on whitespace between sentences.
        """, 
        re.IGNORECASE | re.VERBOSE)
    sentenceList = sentenceEnders.split(paragraph)
    return sentenceList

if __name__ == '__main__':
    f = open("bs.txt", 'r')
    text = f.read()
    mylist = []
    sentences = splitParagraphIntoSentences(text)
    for s in sentences:
        mylist.append(s.strip())
    for i in mylist:
        print i

特殊なケースがどのように処理されるかを確認でき、必要に応じてそれらを簡単に追加または削除できます。サンプル段落を正しく解析します。また、次のテスト パラグラフ (より特殊なケースを含む) を正しく解析します。

これが一文です。二文!三文?文「四」。文「5」!「六」という文?文「7」。センテンス「エイト!」ジョーンズ博士は、「スミス夫人には素敵な娘がいます!」と言いました。

ただし、Riccardo Murri が正しく指摘した、失敗する可能性のある他の例外があることに注意してください。

于 2011-12-11T19:21:44.353 に答える
2

例として投稿した段落では、最初の文が二重引用符"で囲まれており、終了引用符はピリオドの直後に来ます:感染."

あなたの正規表現[.!?]\s{1,2}は、ピリオドの後に文末として 1 つまたは 2 つのスペースが続くものを探しているので、それをキャッチしません。

オプションの終了引用符を許可することで、このケースに対処するように調整できます。

sentenceEnders = re.compile(r'''[.!?]['"]?\s{1,2}(?=[A-Z])''')

ただし、上記の正規表現を使用すると、文から最後の引用符が削除されます。それを保持するのは少しトリッキーで、後読みアサーションを使用して行うことができます。

sentenceEnders = re.compile(r'''(?<=[.!?]['"\s])\s*(?=[A-Z])''')

ただし、正規表現ベースのスプリッターが失敗する多くのケースがあることに注意してください。

  • 略語: "In the works of Dr. AB Givental ..." -- 正規表現によると、これは"Dr." の後に誤って分割されます 。、「あ」「B.」(1 文字の大文字と小文字を調整することはできますが、ハードコーディングしない限り、省略形を検出することはできません。)

  • センテンスの途中での感嘆符の使用: 「... いつ、見よ! M. Deshayes 自身が現れた...」

  • 複数の引用符やネストされた引用符などの使用。

于 2011-12-11T16:39:07.710 に答える
0

はい、何か問題があります。区切り記号は、その後に 1 つまたは 2 つのスペースと大文字が続く場合にのみ考慮に入れられるため、「新しいタイプのワクチンですか?」の末尾になります。たとえば、文は一致しません。

意図的である場合を除き (テキストが適切にフォーマットされていない可能性があります)、スペースについても制限しすぎません。分割されません。

私もあなたの例を理解していません。最初の文だけが " で囲まれているのはなぜですか?

ともかく:

>>> Text="""But in the case of malaria infections, dendritic cells and stuff.
            A new type of vaccine? My uncle!
         """
>>> Sentences = re.split('[?!.][\s]*',Text)
>>> Sentences
    ['But in the case of malaria infections, dendritic cells and stuff',
     'A new type of vaccine',
     'My uncle',
     '']

空の文をフィルタリングすることもできます。

>>> NonemptyS = [ s for s in Senteces if s ]
于 2011-12-11T16:37:39.837 に答える