如何将段落分割成以句号(.)为分隔符的句子,但当句号是缩写的一部分时除外?

3
考虑以下文本段落
保护组织称20年禁令对美国标志性物种具有至关重要的保护意义。采矿业和一些共和党议员表示,这对亚利桑那州的经济和美国的能源独立性有害。“尽管受到采矿业的巨大压力,但总统和沙拉扎尔国务卿并没有退缩,”皮尤环境集团美国公共土地主任简·丹诺威茨说。
在上述内容中,容易根据句号(.)分割句子,但是当处理U.S.A.中的句点时,这将导致不正确的结果。假设我有一个缩写列表。
String abbrev[] ={"u.s.a", "u.a.e", "u.k", "p.r.c","u.s.s.r", };
String regex= "\\.";
Pattern pattern = Pattern.compile(regex,Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(sx);
int beginIndex=0;

// Check all occurance
int index=0;
while (matcher.find()) {
    System.out.print("Start index: " + matcher.start());
    System.out.print(" End index: " + matcher.end() + " ");

    String group=matcher.group();
    System.out.println("group: " + group);
    int dotIndex= group.indexOf(".");
    String sub= sx.substring(beginIndex, matcher.start()+dotIndex);
    beginIndex= matcher.start()+dotIndex;

    System.out.println(sub);
}            

我可以尝试使用所有在dotIndex周围的缩写进行暴力匹配。是否有更好的方法?


你能否仅利用常规句子后面的空间,还是存在其他边界条件? - Amish Programmer
@JoshG:我考虑过这个问题,但其他情况怎么办?例如,像“e.g.”和一个空格的这个例子。你需要根据前面的内容进行验证或否定,比如(?<!\.[a-z])\.\s(需要在没有句点和字母前导的情况下有一个句点和空格)。 - Brad Christie
1
你打算如何区分句子中间的缩写和句子末尾的缩写?例如,“我住在美国”。 - Adrian McCarthy
2个回答

3

我的最佳猜测是这样的:(?<!\.[a-zA-Z])\.(?![a-zA-Z]\.),它的意思是:

(?<!\.[a-zA-Z])    # can't be preceded by a period followed by a single letter
\.
(?![a-zA-Z]\.)     # nor can it be followed by a letter and another preiod

然后你可以从那里执行替换。
演示
这将需要更多的努力,如果你需要在引号内捕获句点,这在上面的模式中没有考虑到。

缩写与...有什么区别? - insipid
@insipid:你可以将量词改为接受 {1,2}(基于一个句子通常不以两个字母的单词结尾),或者在每个实例之前捕获单词并将其与异常列表(包括缩写诸如 vs)进行测试,然后再进行解析。 - Brad Christie
@Brad:那英寸(inches)呢?可能有两种情况吧。仅将它添加到白名单还不够。 - cHao
1
@CHao:解析文本是一项全职工作。你几乎总能做到80%的程度,但要达到99/100%的标准就很困难了。 - Brad Christie

1

这个问题无法仅凭正则表达式来解决。判断一个句子是否在任何给定的句点结束并不简单。缩写可能是句子的结尾,也可能不是。省略号可能写成三个句点(或者,在某些情况下,四个,取决于当前的风格)。有时,句子在标点符号(取决于当前的风格)后面的闭合引号之后结束。

您可以使用启发式算法来大多数情况下得到正确答案。但这更像是一个统计问题而不是正则表达式问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接