Как определить предложения без комментариев и уценки с помощью регулярных выражений Javascript? - PullRequest
0 голосов
/ 27 октября 2018

Проблема

У меня есть кусок текста.Он может содержать каждый символ от ASCII 32 (пробел) до ASCII 126 (тильда), включая ASCII 9 (горизонтальная табуляция).

Текст может содержать предложения.Каждое предложение заканчивается точкой, вопросительным знаком или восклицательным знаком, за которым непосредственно следует пробел.

Текст может содержать базовый стиль уценки, а именно: жирный текст (**, также __), курсив(*, также _) и зачеркивание (~~).Уценка может происходить внутри предложений (например, **this** is a sentence.) или вне их (например, **this is a sentence!**).Уценка может не встречаться в предложениях, то есть может не иметь такой ситуации: **sentence. sente** nce..Уценка может включать более одного предложения, то есть может быть в такой ситуации: **sentence. sentence.**.

Также может содержать две последовательности символов: <!-- и -->.Все между этими последовательностями рассматривается как комментарий (как в HTML).Комментарии могут появляться в каждой позиции в тексте, но не могут содержать символы новой строки (я надеюсь, что в Linux это просто ASCII 10).

Я хочу обнаружить в Javascript все предложения и для каждого изони помещают его длину после этого предложения в комментарии, например так: sentence.<!-- 9 -->. В основном, мне все равно, включает ли их длина длину тегов уценки или нет, но было бы неплохо, если бы это не так.

Что я уже сделал?

На данный момент, с помощью этого ответа , я подготовил следующее регулярное выражение для определения предложений.Он в основном соответствует моим потребностям - за исключением того, что он включает комментарии.

const basicSentence = /(?:^|\n| )(?:[^.!?]|[.!?][^ *_~\n])+[.!?]/gi;

Я также подготовил следующее регулярное выражение для обнаружения комментариев.Это также работает, как и ожидалось, по крайней мере, в моих собственных тестах.

const comment = /<!--.*?-->/gi;

Пример

Чтобы лучше увидеть, чего я хочу достичь, давайте приведем пример.Скажем, у меня есть следующий фрагмент текста:

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

foo2bar!

(в конце есть также новая строка, но я не знаю, как добавить пустую строку в уценке Stackoverflow.)

И ожидаемый результат:

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

foo2bar!<!-- 12 -->

(На этот раз нет также перевод строки в конце.)


ОБНОВЛЕНИЕ: Извините, я исправил ожидаемый результат в примере.

1 Ответ

0 голосов
/ 27 октября 2018

Передайте обратный вызов .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

...