如何使用 Javascript 正则表达式检测没有评论和降价的句子?
How to detect sentences without comments and markdown using Javascript regex?
问题
我有一段文字。它可以包含从 ASCII 32 (space) 到 ASCII 126(波浪号)的所有字符,包括 ASCII 9(水平制表符)。
文本中可能包含句子。每句话以点、问号或感叹号结尾,紧跟space.
文本可能包含基本的 markdown 样式,即:粗体文本(**
,也__
),斜体文本(*
,也_
)和删除线 (~~
)。 Markdown 可能出现在句子内部(例如 **this** is a sentence.
)或句子外部(例如 **this is a sentence!**
)。 Markdown可能不会出现跨句,也就是不一定会出现这样的情况:**sentence. sente** nce.
。 Markdown可能包含不止一句话,也就是说,有可能这样的情况:**sentence. sentence.**
.
它还可以包含两个字符序列:<!--
和 -->
。这些序列之间的所有内容都被视为注释(如 HTML)。注释可以出现在文本的每个位置,但不能包含换行符(我希望在 Linux 上它只是 ASCII 10)。
我想检测 Javascript 中的所有句子,并将每个句子的长度放在评论中的这句话之后,如下所示:sentence.<!-- 9 -->
. 主要是,我不在乎它们的长度是否包含 markdown 标签的长度,但如果不包含就好了。
到目前为止我做了什么?
到目前为止,在这个answer的帮助下,我准备了以下用于检测句子的正则表达式。它最符合我的需要——除了它包含评论。
const basicSentence = /(?:^|\n| )(?:[^.!?]|[.!?][^ *_~\n])+[.!?]/gi;
我还准备了以下用于检测评论的正则表达式。它也按预期工作,至少在我自己的测试中是这样。
const comment = /<!--.*?-->/gi;
例子
为了更好地了解我想要实现的目标,让我们举个例子。说,我有以下一段文字:
foo0
b<!-- comment -->ar.
foo1 bar?
<!-- comment -->
foo2bar!
(最后还有一个换行符,但我不知道如何在Whosebug markdown中添加一个空行。)
预期结果是:
foo0
b<!-- comment -->ar.<!-- 10 -->
foo1 bar?<!-- 9 -->
<!-- comment -->
foo2bar!<!-- 12 -->
(这次,没有,最后还有换行符。)
更新:抱歉,我已经更正了示例中的预期结果。
将回调传递给 .replace
,用空字符串替换所有注释,然后 returns 生成的修剪匹配的长度:
const input = `foo0
b<!-- comment -->ar.
foo1 bar?
<!-- comment -->
foo2bar!
`;
const output = input.replace(
/(?:^|\n| )(?:[^.!?]|[.!?][^ *_~\n])+[.!?]/g,
(match) => {
const matchWithoutComments = match.replace(/<!--.*?-->/g, '');
return `${match}<!-- ${matchWithoutComments.length} -->`;
}
);
console.log(output);
当然,如果您愿意,您也可以使用类似的模式将 markdown 符号替换为内部文本内容:
.replace(/([*_]{1,2}|~~)((.|\n)*?)/g, '')
(由于嵌套和可能不平衡的标签,正则表达式不太适合使用,您可能必须重复该行,直到找不到进一步的替换)
此外,根据评论,您当前的正则表达式要求每个句子都以 .
、!
或 ?
结尾。 <!--
中的评论 !
被视为(短)句的结尾。一种选择是先行查找 whitespace(space 或换行符)或正则表达式末尾的输入末尾:
const input = `foo0
b<!-- comment -->ar.
foo1 bar?
<!-- comment -->
foo2bar!
<!-- comment -->`;
const output = input.replace(
/(?:^|\n| )(?:[^.!?]|[.!?][^ *_~\n])+[.!?](?=\s|$|[*_~])/g,
(match) => {
const matchWithoutComments = match.replace(/<!--.*?-->/g, '');
return `${match}<!-- ${matchWithoutComments.length} -->`;
}
);
console.log(output);
问题
我有一段文字。它可以包含从 ASCII 32 (space) 到 ASCII 126(波浪号)的所有字符,包括 ASCII 9(水平制表符)。
文本中可能包含句子。每句话以点、问号或感叹号结尾,紧跟space.
文本可能包含基本的 markdown 样式,即:粗体文本(**
,也__
),斜体文本(*
,也_
)和删除线 (~~
)。 Markdown 可能出现在句子内部(例如 **this** is a sentence.
)或句子外部(例如 **this is a sentence!**
)。 Markdown可能不会出现跨句,也就是不一定会出现这样的情况:**sentence. sente** nce.
。 Markdown可能包含不止一句话,也就是说,有可能这样的情况:**sentence. sentence.**
.
它还可以包含两个字符序列:<!--
和 -->
。这些序列之间的所有内容都被视为注释(如 HTML)。注释可以出现在文本的每个位置,但不能包含换行符(我希望在 Linux 上它只是 ASCII 10)。
我想检测 Javascript 中的所有句子,并将每个句子的长度放在评论中的这句话之后,如下所示:sentence.<!-- 9 -->
. 主要是,我不在乎它们的长度是否包含 markdown 标签的长度,但如果不包含就好了。
到目前为止我做了什么?
到目前为止,在这个answer的帮助下,我准备了以下用于检测句子的正则表达式。它最符合我的需要——除了它包含评论。
const basicSentence = /(?:^|\n| )(?:[^.!?]|[.!?][^ *_~\n])+[.!?]/gi;
我还准备了以下用于检测评论的正则表达式。它也按预期工作,至少在我自己的测试中是这样。
const comment = /<!--.*?-->/gi;
例子
为了更好地了解我想要实现的目标,让我们举个例子。说,我有以下一段文字:
foo0
b<!-- comment -->ar.
foo1 bar?
<!-- comment -->
foo2bar!
(最后还有一个换行符,但我不知道如何在Whosebug markdown中添加一个空行。)
预期结果是:
foo0
b<!-- comment -->ar.<!-- 10 -->
foo1 bar?<!-- 9 -->
<!-- comment -->
foo2bar!<!-- 12 -->
(这次,没有,最后还有换行符。)
更新:抱歉,我已经更正了示例中的预期结果。
将回调传递给 .replace
,用空字符串替换所有注释,然后 returns 生成的修剪匹配的长度:
const input = `foo0
b<!-- comment -->ar.
foo1 bar?
<!-- comment -->
foo2bar!
`;
const output = input.replace(
/(?:^|\n| )(?:[^.!?]|[.!?][^ *_~\n])+[.!?]/g,
(match) => {
const matchWithoutComments = match.replace(/<!--.*?-->/g, '');
return `${match}<!-- ${matchWithoutComments.length} -->`;
}
);
console.log(output);
当然,如果您愿意,您也可以使用类似的模式将 markdown 符号替换为内部文本内容:
.replace(/([*_]{1,2}|~~)((.|\n)*?)/g, '')
(由于嵌套和可能不平衡的标签,正则表达式不太适合使用,您可能必须重复该行,直到找不到进一步的替换)
此外,根据评论,您当前的正则表达式要求每个句子都以 .
、!
或 ?
结尾。 <!--
中的评论 !
被视为(短)句的结尾。一种选择是先行查找 whitespace(space 或换行符)或正则表达式末尾的输入末尾:
const input = `foo0
b<!-- comment -->ar.
foo1 bar?
<!-- comment -->
foo2bar!
<!-- comment -->`;
const output = input.replace(
/(?:^|\n| )(?:[^.!?]|[.!?][^ *_~\n])+[.!?](?=\s|$|[*_~])/g,
(match) => {
const matchWithoutComments = match.replace(/<!--.*?-->/g, '');
return `${match}<!-- ${matchWithoutComments.length} -->`;
}
);
console.log(output);