如何使用正则表达式选择一段文本中的第一个句子?

时间:2015-09-07 21:37:04

标签: c# .net regex

我的任务是从文本中选择第一句话(我在C#写作)。我认为最合适的方式是使用regex,但发生了一些麻烦。我应该用什么正则表达式来选择第一句话?

几个例子:

  1. 输入:“我是狮子,我想要自由。当你看到我的内心时,你看到狮子吗?”预期结果:“我是狮子,我希望自由。”
  2. 输入:“我喝得太多,他们叫我查理4.0手。任何文字。”预期结果:“我喝得太多,他们称我为查理4.0手。”
  3. 输入:“所以拿出你的手然后把HU扔了。”现在挥动它就像你不假装一样!'“预期的结果:”所以拿出你的手然后把胡子扔掉。“ / LI>

    第三个让我很困惑。

3 个答案:

答案 0 :(得分:1)

因为你已经提供了一些假设:

  

句子用空格划分   任务是选择第一句

您可以使用以下正则表达式:

^.*?[.?!](?=\s+(?:$|\p{P}*\p{Lu}))

请参阅RegexStorm demo

正则表达式细分:

  • ^ - 字符串的开头(因此,只匹配第一个句子)
  • .*? - 尽可能少的任意数量的字符(使用RegexOptions.Singleline也可以将换行符与.匹配)
  • [.?!] - 最后一个标点符号
  • (?=\s+(?:$|\p{P}*\p{Lu})) - 预测确保在字符串结尾(\s+)或可选标点符号({{1)之后有一个或多个空白符号($) }和)大写字母(\p{P})。

<强>更新

因为事实证明你可以输入单句,而你的句子可以以任何字母或数字开头,你可以使用

\p{Lu}

请参阅another demo

答案 1 :(得分:-1)

我提出了一个使用大量负面预测的正则表达式来排除某些情况,例如:标点符号必须后面跟小写字符,或大写字母未关闭句子之前的点。这会将所有文本分成单独的句子。如果给你一个文本,只需参加第一场比赛。

[\s\S]*?(?![A-Z]+)(?:\.|\?|\!)(?!(?:\d|[A-Z]))(?! [a-z])/gm

regex

答案 2 :(得分:-1)

应使用以下扫描仪搜索句子分隔符:

  • 如果它是sentence-finisher字符(如[。!?])
    • 必须后跟空格或允许的字符序列,然后是空格:
      • 像'。'的序列为'。' (A sentence...
      • ...或'!'的序列和/或'?'为'!'和'?' (Exclamation here!?
    • 然后必须遵循:
      • 大写字符(忽略引号,如果有的话)
      • 数字
        • 必须后跟小写或其他sentence-finister
      • dialog-starter字符(Blah blah blah... - And what next, Elric?

提示:不要忘记在输入源字符串中添加额外的空格字符。

<强> UPD:

一些野生伪代码xD:

func sentence(inputString) {
    finishers = ['.', '!', '?']

    allowedSequences = ['.' => ['..'], '!' => ['!!', '?'], '?' => ['??', '!']]

    input = inputString
    result = ''

    found = false
    while input != '' {

        finisherPos = min(pos(input, finishers))

        if !finisherPos
            return inputString

        result += substr(input, 0, finisherPos + 1)
        input = substr(input, finisherPos)

        p = finisherPos

            finisher = input[p]

            p++

            if input[p] != ' '
                if match = testSequence(substr(input, p), allowedSequences[finisher]) {
                    result += match
                    found = true
                    break
                } else {
                    continue
                }
            else {
                p++
                if input[p] in [A-Z] {
                    found = true
                    break
                }

                if input[p] in [0-9] {
                    p++
                    if input[p] in [a-z] or input[p] in finishers {
                        found = true
                        break
                    }
                    p--
                }

                if input[p] in ['-'] {
                    found = true;
                    break
                }
            }

    }

    if !found 
        return inputStr

    return result
}

func testSequence(str, sequences) {
    foreach (sequence: sequences)
        if startsWith(str, sequence)
            return sequence

    return false
}