我正在为书籍制作处理系统,作为其中的一部分,我需要一个强大的算法来将文本分成句子。
直接的方法是根据角色的出现简单地分割文本。但是很多书都大量使用引号,这并没有给出正确的结果。考虑一下这句话:
'加油!'他喊道。他很不高兴。
将分成
虽然我们想要这个结果:
现在,我们可以检测到了。?!字符在引号内,并且永远不会在引用的文本中分割,但是检测引号内的内容并不是微不足道的。考虑一下这句话:
'发生了什么事?'他问道。
这需要我们检测一个quatation mark和一个用于其他目的的撇号之间的区别,例如“那个”,“69'ers'”,“他'n'Hers'”等等。
我们无法控制使用何种引号。 Could be "quote", ‘quote’, 'quote', “quote”.
撇号字符如"that's" or "that’s"
...如果差异在这里不容易看到,我很抱歉,但是使用了很多不同的引号字符。
其中许多案件都是微不足道的,但我们也必须处理最坏情况下的scanerios,就像之前的例子一样。
至少在大多数情况下,报价的开头是与报价结尾不同的字符。例如:
'我们会在几个小时后回来。'
所以,这给了我们一个非常可靠的迹象,表明报价至少何时开始。虽然,目前还不清楚哪个角色会结束引用。
任何人都知道一个好的解决方案吗?
编辑:我现有的代码,处理引用字符与使用的撇号不同的最简单的情况:
public static List<string> splitSentences(string text)
{
List<string> sentences = new List<string>();
StringBuilder sb = new StringBuilder();
bool insideQuote = false;
for (int i=0;i<text.Length;i++)
{
char c = text[i];
//Handle quotes properly
if (isQuote(c))
insideQuote = !insideQuote;
sb.Append(c);
if ( !insideQuote && isSentenceDelimiter(c) )
{
string s = sb.ToString().Trim();
if (s.Length>0)
sentences.Add(s);
sb.Clear();
insideQuote = false;
}
}
if (sb.Length > 0)
{
string s = sb.ToString().Trim();
if (s.Length > 0)
sentences.Add(s);
}
return sentences;
}
private static char[] splitter = new char[] { '.', '!', '?', '。', '!', '?', '\n', '\r' };
private static bool isSentenceDelimiter(char c)
{
foreach (char d in splitter)
if (d.Equals(c))
return true;
return false;
}
private static char[] quotechar = new char[] { '"', '“', '”' };
private static bool isQuote(char c)
{
foreach (char d in quotechar)
if (d.Equals(c))
return true;
return false;
}