23

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

我要做的是:

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"
]

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

4

8 回答 8

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


替换操作使用:

"$1|"

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

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


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

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

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

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

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

从那里:

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

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

于 2013-09-20T10:46:21.647 回答
13
str.replace(/(\.+|\:|\!|\?)(\"*|\'*|\)*|}*|]*)(\s|\n|\r|\r\n)/gm, "$1$2|").split("|")

RegExp(参见Debuggex):

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

评论:

  • 如果您使用 (?=[AZ]),则 RegExp 在某些语言中将无法正常工作。例如“Ü”、“Č”或“Á”将不会被识别。
于 2015-07-15T12:27:30.930 回答
7

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

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

正则表达式可视化

调试演示

它拆分此文本

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

于 2013-09-20T10:54:54.463 回答
5

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

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."]
于 2013-09-20T10:40:50.633 回答
4

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

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);

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

于 2013-09-20T10:41:55.267 回答
3

你忘了把'\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/

于 2013-09-20T10:55:31.053 回答
3

我只是改变字符串并在每个句子之间放一些东西。您告诉我您有权更改它们,因此这样做会更容易。

\r\n

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

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

于 2013-09-20T11:01:43.873 回答
0

@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));

于 2020-11-25T11:43:57.107 回答