BASH: поиск строки и точное отображение точного количества подстрок внутри нее - PullRequest
0 голосов
/ 27 апреля 2018

Я искал по всему и до сих пор не могу найти этот простой ответ. Я уверен, что это так просто. Пожалуйста, помогите, если вы знаете, как это сделать.

sample.txt:

AAAAA

Я хочу найти точное время, когда происходит комбинация «ААА». Если вы просто используете, например,

grep -o 'AAA' sample.txt | wc -l

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

Я ищу наиболее сжатое в / большинство возможностей / буквальное точное число вхождений, начиная с каждого отдельного символа «AAA» в sample.txt, а не просто блоки каждого раза, когда он находит это, как это делает в обычном тексте поиск по типу редактора из окна поиска.

Как нам этого добиться, желательно в AWK? SED, GREP и все остальное прекрасно, и я могу включить их в скрипт Bash.

Ответы [ 4 ]

0 голосов
/ 27 апреля 2018

Я разместил это в другом посте OP, но это было проигнорировано, возможно, потому что я не добавил примечания и объяснения. Просто другой подход и любые обсуждения приветствуются.

$ awk -v sample="$(<sample.txt)" '{ x=sample; n=0 }$0 != ""{
    while(t=index(x,$0)){ n++; x=substr(x,t+1) } 
    print $0,n
}' combinations

Пояснение:

Переменные:

  • sample: необработанный фрагмент текста из файла sample.txt с аргументом -v
  • x: строка назначения, перед каждым тестом значение сбрасывается на sample
  • $0: тестовая строка из файла combination, каждая строка содержит тестовую строку
  • n: счетчик количества вхождений тестовой строки ($ 0)
  • t: позиция первого символа совпадающей тестовой строки ($ 0) в целевой строке (x)

Обновление: Добавлено $0 != "" перед основным циклом while, чтобы пропустить пустые строки, которые ведут к неограниченному циклу.

код:

    awk -v sample="$(<sample.txt)"   '

        # reset the targeting string(with the sample text) and the counter "n" 
        { x = sample; n = 0 }  

        # below the main block where $0 != "" to skip the EMPTY testing string
        ($0 != ""){
            # the function index(x, $0) returns the position(assigned to "t") of the first character 
            # of the matched testing string($0) in the targeting string(x). 
            # when no match is found, it returns zero and thus step out of the while loop.
            while(t=index(x,$0)) {
                n++;                # increment the number of matches 
                x = substr(x, t+1)  # modify the targeting string to remove all characters before the position(t) inclusively 
            }
            print $0, n             # print the testing string and the counts 
        }
    ' combinations

awk index () - это функция, намного более быстрая, чем совпадения с регулярными выражениями, и она не требует дорогостоящих сравнений строк методом грубой силы. Прилагается проверенный файл sample.txt и их комбинации:

$ more sample.txt 
AAAAAHHHAAHH
HAAAAHHHAAHH
AAHH

$ more combinations 
AA
HH
AAA
HHH
AAH
HHA
ZK

Протестированная среда: GNU Awk 4.0.2, Centos 7.3

0 голосов
/ 27 апреля 2018

Это версия awk

echo "AAAAA AAA AAAABBAAA"  \
| gawk -v pat="AAA" '{ 
    for(i=1; i<=NF; i++){
        # current field length
        m=length($i)
        #search pattern length
        n=length(pat)
        for(l=1 ; l<m; l++){
            sstr=substr($i,l,n)
            #print i " " $i " sub:" sstr

            # substring matches pattern
            if(sstr ~ pat){
                count++
            }else{
                print "contiguous count on field " i " = " count
                # uncomment next line if non-contiguous matches are not needed
                #break
            }
        }
        print "total count on field " i " = " count
        count=0
    }

}'
0 голосов
/ 27 апреля 2018

Это может работать для вас (GNU sed & wc):

sed -r 's/^[^A]*(AA?[^A]+)*AAA/AAA\nAA/;/^AAA/P;D' | wc -l

Потеряйте любые символы, кроме A и одинарные или двойные A. Затем выведите тройной A, потеряете первый A и повторите. Наконец подсчитайте количество напечатанных строк.

0 голосов
/ 27 апреля 2018

Это не тривиальная проблема в bash. Насколько я знаю, стандартные утилиты не поддерживают этот вид поиска. Однако вы можете использовать стандартные функции bash для реализации этого поведения в функции. Вот как я мог бы атаковать проблему, но есть и другие способы:

#!/bin/bash

search_term="AAA"
text=$(cat sample.txt)
term_len=${#search_term}
occurences=0

# While the text is greater than or equal to the search term length
while [ "${#text}" -ge "$term_len" ]; do

    # Look at just the length of the search term
    text_substr=${text:0:${term_len}}

    # If we see the search term, increment occurences
    if [ "$text_substr" = "$search_term" ]; then
        ((occurences++))
    fi

    # Remove the first character from the main text
    # (e.g. "AAAAA" becomes "AAAA")
    text=${text:1}
done

printf "%d occurences of %s\n" "$occurences" "$search_term"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...