Как проверить, состоит ли выделенный текст в Интернете только из слов в JavaScript? - PullRequest
0 голосов
/ 24 ноября 2018

В vanilla Javascript я пытаюсь определить, состоит ли весь текст, выбранный пользователем на веб-странице, в словах (исключая символы).

В качестве примера:

Давайтескажем, у нас есть тексты, подобные приведенным ниже, где-то на веб-странице.

Здравствуйте, текст для примера! (Когда выбрано все)

Должен привести к ['Hello', 'a', 'text', 'for', 'the', 'example']

Тем не менее,

Hel lo, текст для примера! (Оставляя первыйтри буквы)

Должно привести к ['a', 'text', 'for', 'the', 'example'], поскольку Hello не было полностью выбрано в качестве слова.

Пока у меня есть функция getSelectionText, которая выводит весь выделенный текст.

function getSelectionText() {
    var text = "";
    if (window.getSelection) {
        text = window.getSelection().toString();
    } else if (document.selection && document.selection.type !== "Control") {
        text = document.selection.createRange().text;
    }
    return text;
}

// Just adding the function as listeners.
document.onmouseup = document.onkeyup = function() {
    console.log(getSelectionText());
};

Есть ли какой-нибудь хороший способ настроить мою функцию, чтобы она работала, как я упоминал?

1 Ответ

0 голосов
/ 24 ноября 2018

Основным препятствием на пути к достижению того, что вы хотите, является то, как сказать вашей программе, что такое «слово» на самом деле.

Один из способов - это получить полный словарь всех английских слов.

const setOfAllEnglishWords = new Set([
  "Hello",
  "a",
  "text",
  "for",
  "the",
  "example"
  // ... many many more
]);

const selection = "lo, a text for the example!";
const result = selection
  .replace(/[^A-Za-z0-9\s]/g, "") // remove punctuation by replacing anything that is not a letter or a digit with the empty string
  .split(/\s+/)                   // split text into words by using 1 or more whitespace as the break point
  .filter(word => setOfAllEnglishWords.has(word));

console.log(result);

Для этого может потребоваться большой объем памяти.Оксфордский словарь английского языка, основанный на быстром поиске в Google, содержит приблизительно 218632 слов.Средняя длина слова составляет 4.5 букв и JS хранит 2 байтов на символ, что дает нам 218632 * (4.5 * 2) = 1967688 B = 1.967 MB, что может занять до 1 минуты для загрузки при медленном соединении 3G.

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

function getSetOfWordsOnPage() {
  const walk = document.createTreeWalker(
    document.body,
    NodeFilter.SHOW_TEXT
  );

  const dict = new Set();
  let n;
  while ((n = walk.nextNode())) {
    for (const word of n.textContent
      .replace(/[^A-Za-z0-9\s]/g, "")
      .split(/\s+/)
      .map(word => word.trim())
      .filter(word => !!word)) {
      dict.add(word);
    }
  }
  return dict;
}

const setOfWordsOnThePage = getSetOfWordsOnPage();

function getSelectionText() {
  if (window.getSelection) {
    return window.getSelection().toString();
  } else if (document.selection && document.selection.type !== "Control") {
    return document.selection.createRange().text;
  }
  return "";
}

// Just adding the function as listeners.
document.querySelector("#button").addEventListener("click", () => {
  const result = getSelectionText()
    .replace(/[^A-Za-z0-9\s]/g, "") // remove punctuation
    .split(/\s+/) // split text into words
    .filter(word => setOfWordsOnThePage.has(word));
  console.log(result);
});
<button id="button">Show result</button>
<p>this is some text</p>
<p>again this is a text!!!!!</p>
<p>another,example,of,a,sentence</p>

Может быть, мы можем пойти еще дальше.Нужно ли помнить слова?Кажется, что определения «слово - это текст, окруженный пробелами» достаточно.

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

Чтобы уменьшитьненужные накладные расходы на запоминание слов на странице, а также на устранение ошибки частичного выбора действительного слова, мы можем проверить содержимое левого (якорного) и самого правого (фокусного) узлов выбранной областисразу после выделения и просто игнорируйте их, если они содержат дополнительный невыбранный текст.

Здесь мы предполагаем, что для любого произвольного выделения текста у нас может быть не более 2 частично выбранных слов, по одному вкаждый конец выбора.

Примечание: подход ниже также обрабатывает заглавные буквы, предполагая, что THIS, tHiS и this - это одно и то же слово.

function removePunctuation(string) {
  return string.replace(/[^A-Za-z0-9\s]/g, " ");
}

function splitIntoWords(string) {
  return removePunctuation(string)
    .split(/\s+/)
    .map(word => word.toLowerCase().trim())
    .filter(word => !!word);
}

function getSelectedWords() {
  const selection = window.getSelection();
  const words = splitIntoWords(selection.toString());

  if (selection.anchorNode) {
    const startingsWords = splitIntoWords(selection.anchorNode.textContent);
    if (words[0] !== startingsWords[0]) {
      words.shift(); // remove the start since it's not a whole word
    }
  }

  if (selection.focusNode) {
    const endingWords = splitIntoWords(selection.focusNode.textContent);
    if (words[words.length - 1] !== endingWords[endingWords.length - 1]) {
      words.pop(); // remove the end since it's not a whole word
    }
  }

  return words;
}

// Just adding the function as listeners.
document.querySelector("#button").addEventListener("click", () => {
  console.log(getSelectedWords());
});
<button id="button">Show result</button>
<p><div>this is</div> <div>some text</div></p>
<p><span>again</span><span> </span><span>this</span><span> </span><span>is</span><span> </span><span>a</span> <span>text</span><span>!!!!!</span></p>
<p>another,example,of,a,sentence</p>

Примечание: этот код будет по-прежнему разбиваться, если ваши слова разбиты на несколько html-элементов, таких как <span>w</span><span>o</span><span>r</span><span>d</span>.Этот сценарий нарушает наше определение слова, и для его решения вам нужно будет также включить некоторый словарь, чтобы проверить правильность слова, по существу объединяя последние 2 решения выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...