Как подсчитать количество вхождений указанных последовательностей символов при редактировании текстовой области?

Я ищу способ автоматически подсчитывать указанные слова в текстовом поле, не нажимая для этого кнопку, и в этом случае автоматически обновлять его, если есть изменения.

Вот мой хаотичный код:

function findWord1() {
  var outputDiv = $('#opening-bracket');
  var searchText = $('#textarea3').val();
  var wordMatch = "[";

  outputDiv.empty();

  var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){ }\|])/g, "\\"), "ig"));
  outputDiv.append('<a>' + (m ? m.length : 0) + '</a>');
}

function findWord2() {
  var outputDiv = $('#closing-bracket');
  var searchText = $('#textarea3').val();
  var wordMatch = "]";

  outputDiv.empty();

  var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
  outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}

function findWord3() {
  var outputDiv = $('#opening-added-bracket');
  var searchText = $('#textarea3').val();
  var wordMatch = "[A>";

  outputDiv.empty();

  var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
  outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}

function findWord4() {
  var outputDiv = $('#closing-added-bracket');
  var searchText = $('#textarea3').val();
  var wordMatch = "lt;A]";

  outputDiv.empty();

  var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
  outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}

function findWord5() {
  var outputDiv = $('#opening-deleted-bracket');
  var searchText = $('#textarea3').val();
  var wordMatch = "[D>";

  outputDiv.empty();

  var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
  outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}

function findWord6() {
  var outputDiv = $('#closing-deleted-bracket');
  var searchText = $('#textarea3').val();
  var wordMatch = "lt;D]";

  outputDiv.empty();

  var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
  outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<button onclick = "findWord1();findWord2();findWord3();findWord4();findWord5();findWord6();">Count</button>

<table>
<thead>
    <tr>
        <th scope = "col">Items</th>
        <th scope = "col">Count</th>
    </tr>
</thead>
<tbody>
    <tr>
        <td>[A&gt;</td>
        <td><a id = "opening-added-bracket"></a></td>
    </tr>
    <tr>
        <td>&lt;A]</td>
        <td><a id = "closing-added-bracket"></a></td>
    </tr>
    <tr>
        <td>[D&gt;</td>
        <td><a id = "opening-deleted-bracket"></a></td>
    </tr>
    <tr>
        <td>&lt;D]</td>
        <td><a id = "closing-deleted-bracket"></a></td>
    </tr>
    <tr>
        <td>[</td>
        <td><a id = "opening-bracket"></a></td>
    </tr>
    <tr>
        <td>]</td>
        <td><a id = "closing-bracket"></a></td>
    </tr>
</tbody>
</table>

<textarea id = "textarea3" rows = "5">
[A>
lt;A]
[D>
lt;D]
</textarea>

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

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

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

isherwood 23.03.2022 21:44

Спасибо за ваш отзыв, это один из моих планов объединить их все под одной функцией, я просто еще не придумал, как я это сделаю..

ixcode 23.03.2022 21:45

Необходимо исправить значения wordMatchfindWord4 и findWord6, а также соответствующие значения текстовой области... &lt;A]/&lt;D] вместо текущего lt;A]/lt;D].

Peter Seliger 24.03.2022 10:36
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
91
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Используйте keyup Просто сделайте так

function countWordFunc() { 

  let myText = document.getElementById("myText").value;

  let wordsArr = myText.trim().split(" ")
  let countWords = wordsArr.filter(word => word !== "").length
  
  let counter = document.getElementById("counter");
  counter.innerHTML = `Total Words: ${countWords}`;

}
<textarea onkeyup = "countWordFunc()" id = "myText">Hello, World</textarea>

<div id = "counter"></div>
"... автоматически считать слова указанный..."
Peter Seliger 23.03.2022 21:42

@GMKHussain ... рассмотрите возможность удаления этого ответа, поскольку он полностью упускает из виду всю проблему и не соответствует ни одному из требований ОП.

Peter Seliger 24.03.2022 02:17
Ответ принят как подходящий

Создайте функцию для вызова всех остальных. Это шаг к упрощению вашего кода. Затем создайте прослушиватель событий для события input текстовой области с новой функцией в качестве обратного вызова.

Этот вопрос, по сути, дублирует многие другие вопросы, связанные с событиями. См. https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events для получения полезной информации и ищите дополнительные ответы здесь, если у вас есть дополнительные вопросы.

function findAllWords() {
  findWord1();
  findWord2();
  findWord3();
  findWord4();
  findWord5();
  findWord6();
}

document.getElementById('textarea3').addEventListener('input', findAllWords);

function findWord1() {
  var outputDiv = $('#opening-bracket');
  var searchText = $('#textarea3').val();
  var wordMatch = "[";

  outputDiv.empty();

  var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){ }\|])/g, "\\"), "ig"));
  outputDiv.append('<a>' + (m ? m.length : 0) + '</a>');
}

function findWord2() {
  var outputDiv = $('#closing-bracket');
  var searchText = $('#textarea3').val();
  var wordMatch = "]";

  outputDiv.empty();

  var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
  outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}

function findWord3() {
  var outputDiv = $('#opening-added-bracket');
  var searchText = $('#textarea3').val();
  var wordMatch = "[A>";

  outputDiv.empty();

  var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
  outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}

function findWord4() {
  var outputDiv = $('#closing-added-bracket');
  var searchText = $('#textarea3').val();
  var wordMatch = "lt;A]";

  outputDiv.empty();

  var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
  outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}

function findWord5() {
  var outputDiv = $('#opening-deleted-bracket');
  var searchText = $('#textarea3').val();
  var wordMatch = "[D>";

  outputDiv.empty();

  var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
  outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}

function findWord6() {
  var outputDiv = $('#closing-deleted-bracket');
  var searchText = $('#textarea3').val();
  var wordMatch = "lt;D]";

  outputDiv.empty();

  var m = searchText.match(new RegExp(wordMatch.toString().replace(/(?=[.\\+*?[^\]$(){}\|])/g, "\\"), "ig"));
  outputDiv.append('<a>' + (m ? m.length : 0) + '</a');
}
<script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<table>
  <thead>
    <tr>
      <th scope = "col">Items</th>
      <th scope = "col">Count</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>[A&gt;</td>
      <td>
        <a id = "opening-added-bracket"></a>
      </td>
    </tr>
    <tr>
      <td>&lt;A]</td>
      <td>
        <a id = "closing-added-bracket"></a>
      </td>
    </tr>
    <tr>
      <td>[D&gt;</td>
      <td>
        <a id = "opening-deleted-bracket"></a>
      </td>
    </tr>
    <tr>
      <td>&lt;D]</td>
      <td>
        <a id = "closing-deleted-bracket"></a>
      </td>
    </tr>
    <tr>
      <td>[</td>
      <td>
        <a id = "opening-bracket"></a>
      </td>
    </tr>
    <tr>
      <td>]</td>
      <td>
        <a id = "closing-bracket"></a>
      </td>
    </tr>
  </tbody>
</table>

<textarea id = "textarea3" rows = "5">
[A>
lt;A]
[D>
lt;D]
</textarea>

Большое спасибо, что нашли время ответить на мой запрос. Это решение именно то, что мне нужно прямо сейчас. Только один вопрос, поскольку я еще не пробовал, я предполагаю, что все еще можно использовать основную функцию findAllWords() для создания кнопки, которая может вручную считать слова? (Это нужно, чтобы сценарий, который у меня есть, программно обновлял текст, и я предполагаю, что он не будет обновлять счетчик после изменения текста).

ixcode 23.03.2022 22:15

Конечно, но используйте прослушиватель событий и для кнопки. Держите свой JavaScript подальше от вашего HTML.

isherwood 23.03.2022 22:17

Попробуйте это, объединив функции в одну:

    let textarea = $('#textarea3');
textarea.on('keyup', _ => counting());
function counting() {
    var searchText = $('#textarea3').val();

    let words = [];
    words['[A>'] = '#opening-added-bracket';
    words['<A]'] = '#closing-added-bracket';
    words['[D>'] = '#opening-deleted-bracket';
    words['<D]'] = '#closing-deleted-bracket';
    words['['] = '#opening-bracket';
    words[']'] = '#closing-bracket';

    for (const word in words) {
        var outputDiv = $(words[word]);
        outputDiv.empty();
        let count = searchText.split(word).length - 1;
        searchText = searchText.replaceAll(word,'');
        outputDiv.append('<a>' + count + '</a>');
    }
}
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button onclick = "counting();">Count</button>

<table>
    <thead>
        <tr>
            <th scope = "col">Items</th>
            <th scope = "col">Count</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>[A&gt;</td>
            <td><a id = "opening-added-bracket"></a></td>
        </tr>
        <tr>
            <td>&lt;A]</td>
            <td><a id = "closing-added-bracket"></a></td>
        </tr>
        <tr>
            <td>[D&gt;</td>
            <td><a id = "opening-deleted-bracket"></a></td>
        </tr>
        <tr>
            <td>&lt;D]</td>
            <td><a id = "closing-deleted-bracket"></a></td>
        </tr>
        <tr>
            <td>[</td>
            <td><a id = "opening-bracket"></a></td>
        </tr>
        <tr>
            <td>]</td>
            <td><a id = "closing-bracket"></a></td>
        </tr>
    </tbody>
</table>

<textarea id = "textarea3" rows = "5">
[A>
<A]
[D>
<D]
</textarea>

В приведенной выше реализации массив words используется как своего рода объектная карта. Можно рассмотреть возможность его изменения соответственно, например. let words = {};

Peter Seliger 24.03.2022 01:59

@ixcode ... еще хуже <A] и <D] вообще не учитываются. Вместо этого количество ] обновляется неправильно... и то же самое относится к [A> и [D>, которые оба неправильно влияют на количество [... что фактически делает весь подход бесполезным.

Peter Seliger 24.03.2022 02:08

Есть следующие проблемы с кодом OP...

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

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

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

  • один напр. можно настроить совпадающие элементы с помощью шаблонов регулярных выражений.

  • кроме того, можно настроить поведение UI/UX компонента, например автоматический подсчет.

  • каждая конфигурация основана на data-* атрибуты и его аналоге HTMLElement. набор данных.

  • из-за вышеприведенного третьего пункта компонент не зависит от своей разметки, пока необходимые атрибуты data-* предоставляются правильно.

Подход также можно резюмировать, как в одном из моих комментариев...

"Initialize a component like structure by reading and computing the config settings, and upon the latter register the count handler with the correct events. The count handler itself then is a straightforward regex based pattern matching (which also works correctly unlike all the other solutions) and count rendering task. Element IDs are not needed, markup is freely selectable, configurations are applied via markup and data attributes. One does not need to touch JS code in order to introduce more to be matched items/words."

function displayItemCount(itemRoot, target) {
  const elmPattern =
    target && itemRoot?.querySelector('[data-reg-pattern]');

  const elmCount =
    elmPattern && itemRoot?.querySelector('[data-match-count]');

  const regXItem =
    elmCount && RegExp(elmPattern.dataset.regPattern, 'g');

  if (regXItem) {
    elmCount.textContent = (target.value.match(regXItem) ?? []).length;
  }
}
function displayItemCountsOfBoundComponentData() {
  const { rootNode, countsTarget } = this;

  rootNode
    .querySelectorAll('[data-item-match]')
    .forEach(itemRoot =>

      displayItemCount(itemRoot, countsTarget)
    );
}

function initializeItemCountsComponent(rootNode) {
  const { dataset } = rootNode;
  let {
    countsTargetSelector = '',
    triggerCountsSelector = '',
    autoCount = false,
  } = dataset;
  
  countsTargetSelector = countsTargetSelector.trim();
  triggerCountsSelector = triggerCountsSelector.trim();

  const countsTarget = (
    rootNode.querySelector(countsTargetSelector || null) ||
    document.querySelector(countsTargetSelector || null)
  );
  if (countsTarget) {

    let countsTriggers = rootNode
      .querySelectorAll(triggerCountsSelector || null);

    if (countsTriggers.length === 0) {
      countsTriggers = document
        .querySelectorAll(triggerCountsSelector || null);
    }
    const isAutoCount = (
      (countsTriggers.length === 0) || (

        (autoCount !== false) && (

          (autoCount.trim() === '') ||
          (autoCount.trim().toLowerCase() === 'true')
        )
      )
    );
    const displayItemCounts =
      displayItemCountsOfBoundComponentData.bind({
        rootNode,
        countsTarget,
      });

    countsTriggers.forEach(elmNode =>
      elmNode
        .addEventListener('click', displayItemCounts)
    );
    if (isAutoCount) {

      countsTarget
        .addEventListener('input', displayItemCounts);

      // trigger component's initial item counts.
      displayItemCounts();
    }
  }
}

function main() {
  document
    .querySelectorAll('[data-item-counts]')
    .forEach(initializeItemCountsComponent);
}
main();
body { margin: 0; }
article { position: relative; display: inline-block; margin: 0 20px 0 0; }
[data-item-counts] { float: left; margin: 0 10px 0 0; }
textarea { margin: 0; }
button { position: absolute; left: 0; top: 175px; }
<article>
  <table
    data-item-counts
    data-counts-target-selector = "#textarea3"
    data-trigger-counts-selector = "#count-textarea3-items"
  >
    <thead>
      <tr>
        <th scope = "col">Items</th>
        <th scope = "col">Count</th>
      </tr>
    </thead>
    <tbody>
      <tr data-item-match>
        <td data-reg-pattern = "\[A>" title = "Opening Added Bracket">[A&gt;</td>
        <td data-match-count>.?.</td>
      </tr>
      <tr data-item-match>
        <td data-reg-pattern = "<A]" title = "Closing Added Bracket">&lt;A]</td>
        <td data-match-count>.?.</td>
      </tr>
      <tr data-item-match>
        <td data-reg-pattern = "\[D>" title = "Opening Deleted Bracket">[D&gt;</td>
        <td data-match-count>.?.</td>
      </tr>
      <tr data-item-match>
        <td data-reg-pattern = "<D]" title = "Closing Deleted Bracket">&lt;D]</td>
        <td data-match-count>.?.</td>
      </tr>
      <tr data-item-match>
        <td data-reg-pattern = "\[(?!A|D)" title = "Opening Bracket">[</td>
        <td data-match-count>.?.</td>
      </tr>
      <tr data-item-match>
        <td data-reg-pattern = "(?<!<A|D)]" title = "Closing Bracket">]</td>
        <td data-match-count>.?.</td>
      </tr>
    </tbody>
  </table>

  <textarea
    id = "textarea3"
    cols = "16"
    rows = "12">
[A&gt;&lt;A][D&gt;&lt;D][[]][]&lt;A][D&gt;

[A&gt;&lt;A][D&gt;&lt;D][[]][]&lt;A][D&gt;

... explicitly triggered count.</textarea>

  <button id = "count-textarea3-items">Count Items</button>
</article>

<article>
  <table
    data-item-counts
    data-counts-target-selector = "#textarea54"
    data-auto-count
  >
    <thead>
      <tr>
        <th scope = "col">Items</th>
        <th scope = "col">Count</th>
      </tr>
    </thead>
    <tbody>
      <tr data-item-match>
        <td data-reg-pattern = "\[A>" title = "Opening Added Bracket">[A&gt;</td>
        <td data-match-count>.?.</td>
      </tr>
      <tr data-item-match>
        <td data-reg-pattern = "<A]" title = "Closing Added Bracket">&lt;A]</td>
        <td data-match-count>.?.</td>
      </tr>
      <tr data-item-match>
        <td data-reg-pattern = "\[D>" title = "Opening Deleted Bracket">[D&gt;</td>
        <td data-match-count>.?.</td>
      </tr>
      <tr data-item-match>
        <td data-reg-pattern = "<D]" title = "Closing Deleted Bracket">&lt;D]</td>
        <td data-match-count>.?.</td>
      </tr>
      <tr data-item-match>
        <td data-reg-pattern = "\[(?!A|D)" title = "Opening Bracket">[</td>
        <td data-match-count>.?.</td>
      </tr>
      <tr data-item-match>
        <td data-reg-pattern = "(?<!<A|D)]" title = "Closing Bracket">]</td>
        <td data-match-count>.?.</td>
      </tr>
    </tbody>
  </table>

  <textarea
    id = "textarea54"
    cols = "16"
    rows = "12"
  >[[]][]&lt;A][D&gt;[A&gt;&lt;A][D&gt;&lt;D]

... auto-count while editing.</textarea>

</article>

Этот вопрос очень прост и не заслуживает таких сложностей.

Younes Bennour 24.03.2022 02:53

@YounesBennour ... В приведенном выше подходе нет ничего сложного. Инициализируйте структуру, подобную компоненту, прочитав и вычислив настройки конфигурации, а затем зарегистрируйте обработчик счетчика с правильными событиями. Тогда сам обработчик count представляет собой простое сопоставление шаблонов на основе регулярных выражений (которое также работает правильно, в отличие от всех других решений) и задачу рендеринга count. Идентификаторы элементов не нужны, разметка выбирается свободно, конфигурации применяются через разметку и атрибуты данных. Не нужно трогать JS-код, чтобы ввести больше совпадающих элементов/слов.

Peter Seliger 24.03.2022 10:20

Другие вопросы по теме