2013-05-16 44 views
2

我有40,000行,需要将每行分成不同的句子。现在,我使用的模式是这样的:在句子中加入句子 - 正则表达式

String patternStr2 = "\\s*[\"']?\\s*([A-Z0-9].*?[\\.\\?!]\\s)['\"]?\\s*"; 

它可以处理几乎所有的句子,但像这样的句子: 美国海军,第一次世界大战 将被分为2个部分:美国和海军,第一次世界大战

有没有解决方案来解决这个问题?

+4

这听起来像是你需要上下文相关的匹配,这是不能用正则表达式来完成的。 – greedybuddha

+1

除非你只想处理'US'(和** no **的其他缩写),这可以很容易地完成:D – gkalpak

+1

作为聪明地试图理解句子结尾属于哪里的替代方法,你可以尝试用手加入基期结束失败的情况。 – greedybuddha

回答

0

String patternStr2 =“(?<!\\..)(?<![A-Z].)[\\.\\?!](?!.\\.)”;然后通过使用java Matcher find()方法,可以得到所有的句子。

2

好吧我认为你应该不是使用正则表达式,但我无法拒绝投入一些。

如果这是很难理解,让我知道,我会添加一些评论...

package test; 

import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

public class Main { 
    private static final Pattern SENTENCE_DELIMITER = 
      Pattern.compile("((.+?)((?<!\\.[A-Z])(\\.\\s)(.+))?)"); 
    public static void main(String[] args) { 
     String lineWithOneSentence = 
       "U.S. Navy, World War I"; 
     String lineWithTwoSentences = 
       "U.S. Navy, World War I. U.S. Air Force, World War III."; 
     Matcher matcher = SENTENCE_DELIMITER.matcher(lineWithOneSentence); 
     if (matcher.matches()) { 
      for (int i = 0; i <= matcher.groupCount(); i++) { 
       switch (i) { 
       case 0: 
        System.out.println("WHOLE MATCH: " + matcher.group(i)); 
        break; 
       case 2: 
        System.out.println("FIRST SENTENCE: "+ matcher.group(i)); 
        break; 
       case 5: 
        System.out.println("SECOND SENTENCE: " + matcher.group(i)); 
       default: 
       } 

      } 
     } 
     matcher = SENTENCE_DELIMITER.matcher(lineWithTwoSentences); 
     if (matcher.matches()) { 
      for (int i = 0; i <= matcher.groupCount(); i++) { 
       switch (i) { 
       case 0: 
        System.out.println("WHOLE MATCH: " + matcher.group(i)); 
        break; 
       case 2: 
        System.out.println("FIRST SENTENCE: "+ matcher.group(i)); 
        break; 
       case 5: 
        System.out.println("SECOND SENTENCE: " + matcher.group(i)); 
       default: 
       } 
      } 
     } 
    } 
} 

这里的解决方法是:

  • 使用组
  • 使用负后面跟着一个空格,以确保它们没有前面跟着一个大写字母的点(如“U * .S * ._”)

这相当矫枉过正,可能会在某个时候出现问题,即如果您的文本不符合标点符号。


输出继电器

WHOLE MATCH: U.S. Navy, World War I 
FIRST SENTENCE: U.S. Navy, World War I 
SECOND SENTENCE: null 
WHOLE MATCH: U.S. Navy, World War I. U.S. Air Force, World War III. 
FIRST SENTENCE: U.S. Navy, World War I 
SECOND SENTENCE: U.S. Air Force, World War III. 
1

为什么你想比赛同时要分裂

使用以下正则表达式:

(?<!\..)\.(?!.\.)

说明:

  1. (?<!\..):负回顾后,检查是否没有一点后面2个字符。

  2. \.:匹配一个点。

  3. (?!.\.):否定向前看,检查前面是否有2个字符没有点。

Online demo

注:不知道如何做到这一点在Java中,但我想你应该尝试(?<!\\..)\\.(?!.\\.)。另外不要忘记加上指向你分裂的句子。

+1

这是一个非常棒的提示,但不能处理像“Dr.Wu is perfect”这样的句子。所以,我做了一些改变,String patternStr2 =“(?<!\\ ..)(?<![A-Z]。)[\\。\\ ?!](?!。\\。)”;然后通过使用java Matcher find()方法,可以得到所有的句子。无论如何,许多非常感谢这个答案! –

+0

@CherryWu不客气:) – HamZa