JavaScript Regex для сопоставления границ слов с диакритическими знаками - PullRequest
1 голос
/ 07 марта 2019

Я должен соответствовать в текстовом документе границы слов для слов, имеющих диакритические знаки. Учитывая токен word, мое регулярное выражение выглядит как

var wordRegex = new RegExp("\\b(" + word + ")\\b", "g");
while ((match = wordRegex.exec(text)) !== null) {
                            if (match.index > (seen.get(token) || -1)) {
                                var wordStart = match.index;
                                var wordEnd = wordStart + token.length - 1;
                                item.characterOffsetBegin = wordStart;
                                item.characterOffsetEnd = wordEnd;

                                seen.set(token, wordEnd);
                                break;
                            }
                        }

Это работает нормально для обычных слов, таких как ciao, casa и т. Д. Но это не сработает, когда в тексте есть такие слова, как però, così и т. Д.

const seen = new Map();
var text = "Ci son macchine nascoste e, però, nascoste male"
var tokens = text.split(/[^a-zA-Z0-9àèéìíîòóùúÀÈÉÌÍÎÒÓÙÚ]+/i)
tokens.forEach((token, tokenIndex) => {
  var item = {
    "index": (tokenIndex + 1),
    "word": token
  }
  var escaped = token.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
  var wordRegex = new RegExp("\\b(" + escaped + ")\\b", "g");
  var match = null;
  console.log(token, "---->", wordRegex)
  while ((match = wordRegex.exec(text)) !== null) {
    console.log("\t---->", match.index)
    if (match.index > (seen.get(token) || -1)) {
      var wordStart = match.index;
      var wordEnd = wordStart + token.length - 1;
      item.characterOffsetBegin = wordStart;
      item.characterOffsetEnd = wordEnd;

      seen.set(token, wordEnd);
      break;
    }
  }
})

Вы можете видеть, как в то время как некоторые слова (например, macchine или nascoste) совпадают, поэтому я получаю match.index, для других слов (например, però) регулярное выражение не работает должным образом и match переменная null:

macchine ----> /\b(macchine)\b/g
    ----> 7
nascoste ----> /\b(nascoste)\b/g
    ----> 16
e, ----> /\b(e\,)\b/g
però, ----> /\b(però\,)\b/g
nascoste ----> /\b(nascoste)\b/g
    ----> 16
    ----> 34

Как написать граничное регулярное выражение, которое тоже поддерживает диакритические знаки?

[UPDATE] Следуя подходу, предложенному в комментариях, я использовал удаление диакритических знаков для каждого слова token перед применением Regex, а затем ко всему text, например:

var normalizedText = removeDiacritics(text);
// for each token...
var escaped = token.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
escaped = removeDiacritics(escaped);
var wordRegex = new RegExp("\\b(" + escaped + ")\\b", "g");
var match = null;
while ((match = wordRegex.exec( normalizedText )) !== null) 
{
                             //...

и на этот раз я получу слова с акцентами, захваченными границами слов \b. Конечно, этот подход не оптимален, потому что removeDiacritics должен применяться для каждого токена, поэтому лучшим решением будет сделать это один раз.

1 Ответ

1 голос
/ 08 марта 2019

Это решение, которое мы предложили в комментариях, чтобы сопоставить слова, имеющие диакритические знаки, с их индексом в тексте:

function removeDiacritics(text) {
  return _.deburr(text)
}

const seen = new Map();
var text = "Ci son macchine nascoste e, però, nascoste male"
var tokens = text.split(/[^a-zA-Z0-9àèéìíîòóùúÀÈÉÌÍÎÒÓÙÚ]+/i)
  var normalizedText = removeDiacritics(text)
  
tokens.forEach((token, tokenIndex) => {
  var item = {
    "index": (tokenIndex + 1),
    "word": removeDiacritics(token)
  }
  var escaped = token.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
  escaped = removeDiacritics(escaped)
  var wordRegex = new RegExp("\\b(" + escaped + ")\\b", "g");
  var match = null;
  console.log(token, "---->", wordRegex)
  while ((match = wordRegex.exec(normalizedText)) !== null) {
    console.log("\t---->", match.index)
    if (match.index > (seen.get(token) || -1)) {
      var wordStart = match.index;
      var wordEnd = wordStart + token.length - 1;
      item.characterOffsetBegin = wordStart;
      item.characterOffsetEnd = wordEnd;

      seen.set(token, wordEnd);
      break;
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...