Подсчет совпадений шаблонов регулярных выражений в одной строке с использованием sed или grep?

#regex #bash #sed #grep #counting

#регулярное выражение #bash #sed #grep #подсчет

Вопрос:

Я хочу подсчитать количество совпадений в одной единственной строке (или во всех строках, поскольку всегда будет только одна строка).

Я хочу подсчитывать не только одно совпадение в строке, как в

 echo "123 123 123" | grep -c -E "123" # Result: 1
  

Лучший пример:

 echo "1 1 2 2 2 5" | grep -c -E '([^ ])( 1){1}' # Result: 1, expected: 2 or 3
  

Комментарии:

1. всегда ли данные разделяются пробелом?

2. Всегда будет только «одни данные», потому что, возможно, я хочу сопоставить 123 123 3 (или 2) раза в 123 123 123 123

3. 1 за вопрос, -1 за странный пример регулярных выражений

Ответ №1:

Вы могли бы использовать grep -o then pipe through wc -l :

 $ echo "123 123 123" | grep -o 123 | wc -l
3
  

Комментарии:

1. Моя версия grep не знает, что -o такое:(

2. Вам нужно попросить Деда Мороза о новом grep в этом году. 🙂

3. @manojlds, у тебя есть egrep ? То же самое будет работать с/ egrep

4. @Mike Pennington — спасибо, egrep говорит то же самое. Я сейчас на Windows, поэтому думаю, что это ожидаемо.

5. @Tylio — это неудивительно, посмотри на свое регулярное выражение. Запрашивается 0 или более экземпляров чего-либо, отличного от пробела, за которым следует пробел, за которым следует первое, что вы снова сопоставили. Примечание: 0 или более . В вашей строке действительно пять таких совпадений (при условии, что вы не перематываете после каждого совпадения). Это: 1) "1 1" (байты 1-3), 2) " " (т. е. нулевые экземпляры чего-либо, что не является пробелом, за которым следует пробел, за которым снова те же нулевые экземпляры — байт 4), 3) "2 2" (байты 5-7), 4) " " (байт 8) и, наконец, 5) " " (байт 10). Уф!

Ответ №2:

Может быть, ниже:

 echo "123 123 123" | sed "s/123 /123n/g" | wc -l
  

(может быть, уродливо, но мой bash fu не настолько хорош)

Комментарии:

1. @Tyilo — что ты пробовал? Я получаю 3 для приведенных выше входных данных

2. Скопировал и вставил ваш код, но теперь я вспоминаю, что мой sed не поддерживает n

Ответ №3:

Может быть, вам сначала следует преобразовать пробелы в новые строки:

 $ echo "1 1 2 2 2 5" | tr ' ' $'n' | grep -c 2
3
  

Ответ №4:

Почему бы не использовать awk? Вы могли бы использовать awk '{print gsub(your_regex,"amp;")}' для печати количества совпадений в каждой строке или awk '{c =gsub(your_regex,"amp;")}END{print c}' для печати общего количества совпадений. Обратите внимание, что относительная скорость может варьироваться в зависимости от того, какая реализация awk используется и какой ввод вводится.

Комментарии:

1. Другим способом gawk является gawk -v FPAT=your_regex '{print NF}' или gawk -v FPAT=your_regex '{c =NF}END{print c}' соответственно.

Ответ №5:

Это может сработать для вас:

 sed -n -e ':a' -e 's/123//p' -e 'ta' file | sed -n '$='
  

GNU sed можно было бы написать:

 sed -n ':;s/123//p;t' file | sed -n '$='
  

Комментарии:

1. Первый скрипт не работает в GNU sed 4.2.2: «sed: не удается найти метку для перехода к a'". It seems to work better, if you replace :ta` by :a . Похоже, скрипты требуют перевода строки в конце ввода. Кроме того, скрипт ничего не выводит, если совпадения не найдены. Тест: printf 123 | sed -n ':;s/123//p;t' | sed -n '$=' ничего не выводит.