Gawk - Regexp - не удается получить результаты - PullRequest
0 голосов
/ 08 марта 2020

У меня есть файл с двумя столбцами с именем names.csv. Поле 1 содержит имена с алфавитными символами. Я пытаюсь найти имена, где символ повторяется, например, V ii jay (а не Vijay)

Команда ниже работает и возвращает все строки в поле 1

gawk "$1 ~ /[a-z]/ {print $0}" names.csv

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

gawk "$1 ~ /[a-z]{1,}/ {print $0}" names.csv

Какая коррекция необходима для получения того, что я ищу for?

Для дальнейшего уточнения, если значения в столбце 1 / поле 1 - Vijay, Viijay и Vijayini, я хочу, чтобы возвращался только Viijay. То есть, только значения, в которых символ («i» в данном примере) повторяется (не «повторяющийся», как в Vijayini, где символ «i» повторяется в строке, но не сгруппирован вместе).

Запрошенные данные для примера:

Vijay 1
Viijay 2
Vijayini 3

и ожидаемый результат:

Viijay 2

Ответы [ 2 ]

1 голос
/ 08 марта 2020

Поскольку awk не поддерживает обратные ссылки в регулярном выражении, лучше использовать для этого grep или sed:

$ grep '^[^[:space:]]*\([a-z]\)\1' file
Viijay 2

$ sed -n '/^[^[:space:]]*\([a-z]\)\1/p' file
Viijay 2

Это может быть только для GNU, проверьте Google.

С помощью awk вам нужно будет сделать что-то вроде следующего, чтобы сначала создать регулярное выражение, которое соответствует 2 повторениям любого символа в вашем указанном c наборе символов a-z:

$ awk '{re=$1; gsub(/[^a-z]/,"",re); gsub(/./,"&{2}|",re); sub(/\|$/,"",re)} $1 ~ re' file
Viijay 2

FYI для создания регулярное выражение из $1, которое будет соответствовать 2 повторениям любого символа, который он содержит, а не только a-z, будет:

re=$1; gsub(/[^\\^]/,"[&]{2}|",re); gsub(/[\\^]/,"\\\\&{2}|",re); sub(/\|$/,"",re);

Вы должны обрабатывать ^ иначе, чем другие символы, так как это единственный символ, который имеет значение, отличное от буквального, когда это первый символ в выражении в скобках (т.е. отрицание), поэтому вам нужно экранировать его с помощью обратного слэ sh, а не помещать его в выражение в скобках, чтобы сделать его буквальный. Вы должны обрабатывать \ иначе, потому что [\] означает то же самое, что и [], который является неопределенным выражением в скобках, потому что [ - это начало, а ] - это только первый символ внутри выражения в скобках, это не ] необходимо прекратить.

1 голос
/ 08 марта 2020

Поскольку регулярное выражение awk не поддерживает обратные ссылки при сопоставлении, вам нужно найти дублированные символы другим способом. Он дублирует каждый символ в $1 и добавляет их в переменную, которая затем сопоставляется с исходной строкой в ​​ie. Viijay -> re="(VV|ii|ii|jj|aa|yy)"; if($1~re)... (обратите внимание, что он не проверяет, находится ли запись уже в re, возможно, вы захотите добавить некоторые проверки, дополнительные замечания по проверке в комментариях):

$ awk '
{                                                 # you should test for empty $1
    re="("                                        # reset re
    for(i=1;i<=length($1);i++)                    # for each char in $1
        re=re (i==1?"":"|") (b=substr($1,i,1)) b  # generate dublicated re entry
    re=re ")"                                     # terminating )
    if($1~re)                                     # match
        print                                     # and print if needed
}' file

Вывод:

Viijay 2

По иронии судьбы или в качестве примера, он не работает на Busybox awk - в котором могут использоваться обратные ссылки Ɑ:

$ busybox awk '$1~"(.)\\1" {print $0}' file
Viijay,2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...