Как вывести число повторений шаблона в регулярном выражении? - PullRequest
0 голосов
/ 19 сентября 2018

Я хотел бы вывести количество повторений шаблона с регулярным выражением.Например, конвертируйте "aaad" в "3xad", "bCCCCC" в "b5xC".Я хочу сделать это в sed или awk.

Я знаю, что могу сопоставить его с (.)\1+ или даже захватить с помощью ((.)\1+).Но как я могу получить время повторения и вставить это значение обратно в строку в регулярном выражении, или в sed, или в awk?

Ответы [ 4 ]

0 голосов
/ 20 сентября 2018

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

$ cat tst.awk
{
    out = ""
    for (pos=1; pos<=length($0); pos+=reps) {
        char = substr($0,pos,1)
        for (reps=1; char == substr($0,pos+reps,1); reps++);
        out = out (reps > 1 ? reps "x" : "") char
    }
    print out
}

$ awk -f tst.awk file
3xad
d3xad3xa
fsdfjs
b5xC
3xad3xa

Выше былоЗапустите пример ввода, который любезно предоставил @Thor:

$ cat file
aaad
daaadaaa
fsdfjs
bCCCCC
aaadaaa

Вышеприведенное будет работать для любых вводимых символов, использующих любой awk в любой оболочке любого блока UNIX.Если вам нужно сделать это без учета регистра, просто бросьте tolower() вокруг каждой стороны сравнения в самом внутреннем цикле for.Если вам нужно, чтобы он работал с многосимвольными строками, вам придется рассказать нам, как определить, где подстроки интересуют начало / конец.

0 голосов
/ 19 сентября 2018

В GNU awk:

$ echo aaadbCCCCCxx |  awk -F '' '{
    for(i=1;i<=NF;i+=RLENGTH) {
        c=$i
        match(substr($0,i),c"+")
        b=b (RLENGTH>1?RLENGTH "x":"") c
    }
    print b
}'
3xadb5xC2xx

Если мета-символы regex хотят быть прочитаны как буквальные символы, как отмечено в комментариях, можно попытаться обнаружить их и избежать (решение ниже является только направленным):

$ echo \\\\\\..**aaadbCCCCC++xx |
awk -F '' '{
    for(i=1;i<=NF;i+=RLENGTH) { 
        c=$i                               
        # print i,c                        # for debugging
        if(c~/[*.\\]/)                     # if c is a regex metachar (not complete)
            c="\\"c                        # escape it
        match(substr($0,i),c"+")           # find all c:s
        b=b (RLENGTH>1?RLENGTH "x":"") $i  # buffer to b
    }
    print b
}'
3x\2x.2x*3xadb5xC2x+2xx
0 голосов
/ 19 сентября 2018

Просто для удовольствия.

С sed это громоздко, но выполнимо.Обратите внимание, что в этом примере используется GNU sed (:

parse.sed

/(.)\1+/ {
  : nextrepetition
  /((.)\2+)/ s//\n\1\n/             # delimit the repetition with new-lines
  h                                 # and store the delimited version
  s/^[^\n]*\n|\n[^\n]*$//g          # now remove prefix and suffix
  b charcount                       # count repetitions
  : aftercharcount                  # return here after counting
  G                                 # append the new-line delimited version

  # Reorganize pattern space to the desired format
  s/^([^\n]+)\n([^\n]*)\n(.)[^\n]+\n/\2\1x\3/

  # Run again if more repetitions exist
  /(.)\1+/b nextrepetition
}

b

# Adapted from the wc -c example in the sed manual
# Ref: https://www.gnu.org/software/sed/manual/sed.html#wc-_002dc
: charcount

s/./a/g

# Do the carry.  The t's and b's are not necessary,
# but they do speed up the thing
t a
: a;  s/aaaaaaaaaa/b/g; t b; b done
: b;  s/bbbbbbbbbb/c/g; t c; b done
: c;  s/cccccccccc/d/g; t d; b done
: d;  s/dddddddddd/e/g; t e; b done
: e;  s/eeeeeeeeee/f/g; t f; b done
: f;  s/ffffffffff/g/g; t g; b done
: g;  s/gggggggggg/h/g; t h; b done
: h;  s/hhhhhhhhhh//g

: done

# On the last line, convert back to decimal

: loop
/a/! s/[b-h]*/&0/
s/aaaaaaaaa/9/
s/aaaaaaaa/8/
s/aaaaaaa/7/
s/aaaaaa/6/
s/aaaaa/5/
s/aaaa/4/
s/aaa/3/
s/aa/2/
s/a/1/

y/bcdefgh/abcdefg/
/[a-h]/ b loop

b aftercharcount

Запустите его так:

sed -Ef parse.sed infile

С помощью infile вот так:

aaad
daaadaaa
fsdfjs
bCCCCC
aaadaaa

Вывод:

3xad
d3xad3xa
fsdfjs
b5xC
3xad3xa
0 голосов
/ 19 сентября 2018

Perl для спасения!

perl -pe 's/((.)\2+)/length($1) . "x$2"/ge'
  • -p читает строку ввода построчно и печатает ее после обработки
  • s/// - замена, аналогичная sed
  • /e делает замену оцененной как код

например

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