【问题标题】:I need a regex to match first sentence of the string我需要一个正则表达式来匹配字符串的第一句
【发布时间】:2011-09-22 16:02:54
【问题描述】:

我正在尝试提出一个匹配字符串第一句的正则表达式。我不需要太复杂的东西,只需要一个以“.”或“!”或“?”结尾的句子,注意后面的空格,这样句子“我需要这个 domain.com!”就会匹配。我也没有在 regexlib.com 上找到任何东西。 到目前为止,我一直坚持这一点:

([^.|?|!]*)[\.\s\?\s\!\s]

它并没有真正起作用。如果我尝试匹配

"I need this domain.com! Another sentence. And another sentence."

我只得到“我需要这个域”。我需要它是“我需要这个 domain.com!”

【问题讨论】:

  • 哪种语言?我怀疑正则表达式是否有正确的方法可以去这里。

标签: regex


【解决方案1】:

试试这个:

^.*?[\.!\?](?:\s|$)

【讨论】:

  • 谢谢,这正是我所需要的。
  • 我会接受它,但由于某种原因我必须等待。另外,说句公道话,我只接受正确答案。
  • 它不适用于'This is first (e.g. 1st) sentence. And the second one.'
【解决方案2】:

这是一个通过原始测试的模式,同时也解决了 Vitali Ponomar 对 manji 答案括号的评论。

^.*?[.!?](?:\s|$)(?!.*\))

这使用negated lookahead 来有效地说:

  1. 从头开始并匹配任意字符,任意次数,但尽可能少地匹配仍然允许以下内容成立。
  2. 我们看到以下字符之一:. ? !
  3. 后跟:空格字符行尾
  4. 不是后跟任何导致 ) 右括号字符的内容。

这利用了这样一个事实,即只要括号组是平衡的,我们就知道括号组在哪里结束。因此,如果由于用户输入或处理不当等原因导致句子格式错误,它可能会失败。

您可以通过断言“句首”标记必须包含大写字符来添加一定程度的保护。

^.*?[.!?](?:\s[A-Z]|$)(?!.*\))

这是可取的原因是,在大多数程序中,在连接它们之前将字符串大写要比确保括号在其中正确平衡要容易得多。

请注意,因为 OP 接受了使用 non-capturing 组的答案,例如 (?:foo),所以我也使用了一个。这将导致“句子开头”标记包含在匹配中。您可能想要也可能不想要这个,这取决于您是仅依赖空格字符还是我添加的大小写检查。

我的建议是不包含它,您可以使用 lookahead 来代替,例如 (?=foo)

^.*?[.!?](?=\s[A-Z]|$)(?!.*\))

现在我们没有在匹配中包含 cruft,让我们来处理第一句后只有一个空格的情况:

^.*?[.!?](?=\s[A-Z]|\s?$)(?!.*\))

现在用这个相当不错的模式进行一些测试:

  • 输入:“我需要这个 domain.com!再来一句。再来一句。”

    匹配:“我需要这个 domain.com!”

  • 输入:“这是第一句(例如第一句)。第二句。”

    匹配:“这是第一个(例如第一个)句子。”

  • 输入:“这是一个损坏的句子(例如第一句。第二句。”

    匹配:“这是一个损坏的(例如第一句话。”

  • 输入:“这会绊倒......大多数。但不是我。”

    匹配:“这会绊倒……最。”

太好了。但仍有一些地方会出现这种情况。例如:引号。句子很复杂!要做到这一点,您确实需要考虑给定语言的整个标点符号规则,然后提出一种算法,该算法不会假设每个人都会始终完美地遵循它们,并在不引入奇怪匹配的情况下使某些部分成为可选部分。一旦你沿着这条路走下去,你最终会得到一个长而难以理解的表达式,其中包含大量 greed operators? 问号的某些用法)。

最后,它主要取决于程序的输入是什么样的,它来自哪里,以及在对它应用复杂的模式匹配之前你可以对它进行多好的预处理。通常,对更小、更简单的模式进行多次传递虽然性能较差,但更可靠、更易读。一种是删除或删除您不关心的内容(如换行符或其他空白字符),然后一种是删除可能的恶意输入痕迹,......等。随着输入的简化,慢慢变得更加复杂。

【讨论】:

  • 谢谢!在将我的头撞到墙上试图修改我现有的正则表达式之后,它认为“D”。在“DC”中一个句子的中间是它的结尾,我终于找到了你的正则表达式,这是唯一一个处理那个相当简单的情况的正则表达式!
【解决方案3】:

尚未测试,但应该可以这样做

^([^.|?|!]+)

问题是 * 匹配零个或多个字符,而 + 匹配至少一个字符

【讨论】:

    【解决方案4】:

    (我将使用 Java 正则表达式语法编写,因为这是我所知道的;出于我们的目的,它应该与您使用的任何其他正则表达式系统相同,但我不是 100% 确定。)

    句子边界的正则表达式显然是[.!?]\s。因此,您希望将所有内容与第一个匹配。 ".+" 贪婪地匹配并匹配到最后一句开头的所有内容。你想要一个不情愿的捕获:

    (.+?)[.!?]\s

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多