【问题标题】:Split string into sentences in javascript在javascript中将字符串拆分为句子
【发布时间】:2013-09-20 10:34:16
【问题描述】:

目前我正在开发一个将长列拆分为短列的应用程序。为此,我将整个文本拆分为单词,但目前我的正则表达式也拆分了数字。

我要做的是:

str = "This is a long string with some numbers [125.000,55 and 140.000] and an end. This is another sentence.";
sentences = str.replace(/\.+/g,'.|').replace(/\?/g,'?|').replace(/\!/g,'!|').split("|");

结果是:

Array [
    "This is a long string with some numbers [125.",
    "000,55 and 140.",
    "000] and an end.",
    " This is another sentence."
]

期望的结果是:

Array [
    "This is a long string with some numbers [125.000, 140.000] and an end.",
    "This is another sentence"
]

我必须如何更改我的正则表达式才能实现这一目标?我需要注意我可能遇到的一些问题吗?或者搜索". ""? ""! " 是否足够好?

【问题讨论】:

  • 你能改变字符串还是这不是一个选项?
  • 您是否正在寻找能够获得所需结果的有效正则表达式(或者)您已经知道这一点并希望就它的其他潜在问题提出建议?
  • @Beejee:我可以操纵字符串。
  • '或者搜索 ". ""? ""! " 是否足够好?' - 不,因为它不允许使用". " 的缩写:“我们应该去联邦调查局还是语法警察?”

标签: javascript regex


【解决方案1】:
str.replace(/([.?!])\s*(?=[A-Z])/g, "$1|").split("|")

输出:

[ 'This is a long string with some numbers [125.000,55 and 140.000] and an end.',
  'This is another sentence.' ]

细分:

([.?!]) = 捕获 .?!

\s* = 在前一个标记 ([.?!]) 之后捕获 0 个或多个空白字符。这说明了与英语语法相匹配的标点符号后面的空格。

(?=[A-Z]) = 仅当下一个字符在 A-Z 范围内(大写 A 到大写 Z)时,前一个标记才匹配。大多数英语句子都以大写字母开头。以前的正则表达式都没有考虑到这一点。


替换操作使用:

"$1|"

我们使用了一个“捕获组”([.?!]),我们捕获了其中一个字符,并将其替换为$1(匹配)加上|。因此,如果我们捕获了?,那么替换将是?|

最后,我们拆分管道| 并得到我们的结果。


所以,本质上,我们要说的是:

1) 查找标点符号(.?! 之一)并捕获它们

2) 标点符号后面可以有空格。

3) 在标点符号之后,我期待一个大写字母。

与之前提供的正则表达式不同,这将正确匹配英语语法。

从那里:

4)我们通过附加一个管道|来替换捕获的标点符号

5) 我们拆分管道以创建句子数组。

【讨论】:

  • 如果句子以数字开头,此解决方案将失败。
  • 你可以修改成这样:/([.?!])\x20{1,2}(?=[A-Z\d])/。但是,这会期望 A) 十进制数字后面没有空格,并且 B) 标点符号后面有一个或两个空格字符。这将符合英语语法。如果您不能接受条件 A,那么您尝试解析的语法就会有歧义。
  • 更多关于计算机科学中的语法歧义:en.wikipedia.org/wiki/Ambiguous_grammar。本质上,在您的情况下,带有小数分隔符的数字和新句子的标点符号需要在语法上是可区分的。我提供的修改后的正则表达式符合英语语法。
  • 我看不出忽略条件 A 如何导致语法模棱两可。点歧义可以通过几个规则来解决(不完美,但仍然是一个非常实用的解决方案):1)两位数之间的点是小数分隔符; 2) 除了两位数字之间的点是标点符号 - 句子分隔符。
  • “我女儿 10 岁。再过 10 年,她将 20 岁。” ?
【解决方案2】:
str.replace(/(\.+|\:|\!|\?)(\"*|\'*|\)*|}*|]*)(\s|\n|\r|\r\n)/gm, "$1$2|").split("|")

RegExp(参见Debuggex):

  • (.+|:|!|\?) = 句子不仅可以以“.”、“!”结尾或“?”,也可以用“...”或“:”
  • (\"|\'|)*|}|]) = 句子可以用引号或括号括起来
  • (\s|\n|\r|\r\n) = 句后必须是空格或行尾
  • g = 全局
  • m = 多行

备注:

  • 如果使用 (?=[A-Z]),RegExp 将无法在某些语言中正常工作。例如。 “Ü”、“Č”或“Á”将无法识别。

【讨论】:

    【解决方案3】:

    您可以利用下一个句子以大写字母或数字开头。

    .*?(?:\.|!|\?)(?:(?= [A-Z0-9])|$)
    

    Debuggex Demo

    分割文本

    This is a long string with some numbers [125.000,55 and 140.000] and an end. This is another sentence. Sencenes beginning with numbers work. 10 people like that.
    

    进入句子:

    This is a long string with some numbers [125.000,55 and 140.000] and an end.
    This is another sentence.
    Sencenes beginning with numbers work.
    10 people like that.
    

    jsfiddle

    【讨论】:

    • 这很棒,我只是注意到它不能处理糟糕的用户输入,例如“Jim 去了商店。Larry 一直睡到 12 点。但 Becky 周末离开了。”但是,这超出了问题的范围。我只是为像我这样可能正在寻找快速正则表达式来处理此问题的任何人提及它。
    • 这个也不处理?或!
    【解决方案4】:

    如果后面没有空格+字字符,则使用前瞻避免替换点:

    sentences = str.replace(/(?=\s*\w)\./g,'.|').replace(/\?/g,'?|').replace(/\!/g,'!|').split("|");
    

    输出:

    ["This is a long string with some numbers [125.000,55 and 140.000] and an end. This is another sentence."]
    

    【讨论】:

      【解决方案5】:

      使用前瞻来确保点后面的不是数字会更安全。

      var str ="This is a long string with some numbers [125.000,55 and 140.000] and an end. This is another sentence."
      
      var sentences = str.replace(/\.(?!\d)/g,'.|');
      console.log(sentences);
      

      如果你想更安全,你也可以检查后面是否是数字,但是由于 JS 不支持后向查找,你需要捕获前一个字符并在替换字符串中使用它。

      var str ="This is another sentence.1 is a good number"
      
      var sentences = str.replace(/\.(?!\d)|([^\d])\.(?=\d)/g,'$1.|');
      console.log(sentences);
      

      一个更简单的解决方案是转义数字中的点(例如,用 $$$$ 替换它们),进行拆分,然后取消转义。

      【讨论】:

      • 这是唯一适合我的。 (第一版)
      【解决方案6】:

      您忘记在您的正则表达式中输入“\s”。

      试试这个

      var str = "This is a long string with some numbers [125.000,55 and 140.000] and an end. This is another sentence.";
      var sentences = str.replace(/\.\s+/g,'.|').replace(/\?\s/g,'?|').replace(/\!\s/g,'!|').split("|");
      console.log(sentences[0]);
      console.log(sentences[1]);
      

      http://jsfiddle.net/hrRrW/

      【讨论】:

        【解决方案7】:

        我会更改字符串并在每个句子之间添加一些内容。 你告诉我你有权改变它们,这样会更容易做到。

        \r\n
        

        通过这样做,您可以搜索一个字符串,并且您不需要使用这些复杂的正则表达式。

        如果您想以更难的方式进行操作,我会使用正则表达式来查找“。” “?” “!”后跟一个大写字母。就像 Tessi 向你展示的那样。

        【讨论】:

          【解决方案8】:

          @Roger Poon 和 @Antonín Slejška 的回答效果很好。

          如果我们添加修剪功能并过滤空字符串会更好:

          const splitBySentence = (str) => {
            return str.replace(/([.?!])(\s)*(?=[A-Z])/g, "$1|")
              .split("|")
              .filter(sentence => !!sentence)
              .map(sentence => sentence.trim());
          }
          

          const splitBySentence = (str) => {
            return str.replace(/([.?!])(\s)*(?=[A-Z])/g, "$1|").split("|").filter(sentence => !!sentence).map(sentence => sentence.trim());
          }
          
          const content = `
          The Times has identified the following reporting anomalies or methodology changes in the data for New York:
          
          May 6: New York State added many deaths from unspecified days after reconciling data from nursing homes and other care facilities.
          
          June 30: New York City released deaths from earlier periods but did not specify when they were from.
          
          Aug. 6: Our database changed to record deaths by New York City residents instead of deaths that took place in New York City.
          
          Aug. 20: New York City removed four previously reported deaths after reviewing records. The state reported four new deaths in other counties.(extracted from NY Times)
          `;
          
          console.log(splitBySentence(content));

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-04-23
            • 1970-01-01
            • 2014-09-26
            • 2015-01-16
            • 2021-08-11
            • 2011-11-25
            相关资源
            最近更新 更多