如何使用Javascript正则表达式检测没有注释和减价的句子?

时间:2018-10-27 00:14:06

标签: javascript regex comments markdown

问题

我有一段文字。它可以包含从ASCII 32(空格)到ASCII 126(波浪号)的每个字符,并包括ASCII 9(水平选项卡)。

文本可能包含句子。每个句子都以点,问号或感叹号结尾,然后紧跟空格。

文本可能包含基本的markdown样式,即:粗体文本(**,也__),斜体文本(*,也_)和删除线(~~)。降价可能发生在句子内部(例如**this** is a sentence.)或句子外部(例如**this is a sentence!**)。降价可能不会出现在句子之间,也就是说,可能不会是这样的情况:**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!

(它的末尾还有一个换行符,但是我不知道如何在Stackoverflow markdown中添加一个空行。)

预期结果是:

foo0 
b<!-- comment -->ar.<!-- 10 -->
foo1 bar?<!-- 9 -->
<!-- comment -->

foo2bar!<!-- 12 -->

(这一次,末尾没有换行( no )。


更新:抱歉,我已更正了示例中的预期结果。

1 个答案:

答案 0 :(得分:3)

将回调传递给.replace,该回调将所有注释替换为空字符串,然后返回所修剪的匹配项的长度:

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

当然,如果您愿意,您也可以使用类似的模式用内部文本内容替换降价表示法:

.replace(/([*_]{1,2}|~~)((.|\n)*?)\1/g, '$2')

(由于嵌套的标签和可能不平衡的标签,正则表达式不能很好地使用它,因此您可能必须重复该行,直到找不到进一步的替换为止)

另外,对于每个注释,您当前的正则表达式期望每个句子以.!?结尾。 !中评论的<!--被视为(短)句子的结尾。一种选择是提前查找空白(空格或换行符)或正则表达式末尾的输入结尾:

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

https://regex101.com/r/RaTIOi/1