verificar se uma string possui um caractere mais de uma vez

4

O título, na verdade, quase explica tudo. Gostaria de verificar se uma string contém uma letra (não uma letra específica, na verdade, qualquer letra) mais de uma vez.

por exemplo:

usuário:

test.sh this list

script:

if [ "$1" has some letter more then once ]
then 
do something
fi
    
por user147266 13.12.2015 / 13:57

3 respostas

4

Você pode usar grep .

O regexp \(.\).* corresponde a qualquer caractere único, seguido por qualquer coisa, seguido pelo mesmo primeiro caractere.

grep retornará sucesso se pelo menos uma linha corresponder à regex.

if echo "$1" | grep -q '\(.\).*' ; then  
  echo "match" ; 
fi

Observe que \(.\) corresponde a qualquer caractere e não a qualquer letra, talvez você tenha que restringir o regex à sua definição específica de " realmente qualquer letra ". Você pode usar algo como \([[:alnum:]]\).* , \([[:alpha:]]\).* ou \([a-df-z1245]\).* .

    
por 13.12.2015 / 14:35
2

Você pode usar fold para imprimir a string um caractere por linha, depois uniq -c para contá-los e awk para imprimir apenas os que apareceram mais de uma vez:

$ string="foobar"
$ fold -w 1 <<< "$string" | sort | uniq -c | awk '$1>1'
      2 o

Ou, se o seu shell não suportar aqui strings:

printf '%s\n' "$string" | fold -w 1 | sort | uniq -c | awk '$1>1'

Em seguida, você pode testar se o comando acima retorna ou não uma string vazia:

$ string="foobar"
$ [ -n "$(fold -w 1 <<<"$string" | sort | uniq -c | awk '$1>1')" ] && echo repeated
repeated

Você pode estendê-lo facilmente para imprimir o caractere repetido e o número de vezes que ele foi repetido:

$ rep="$(fold -w 1 <<<"$string" | sort | uniq -c | awk '$1>1')"
$ [ -n "$rep" ] && printf -- "%s\n" "$rep"
    2 o
    
por 13.12.2015 / 15:21
2
c=$(expr " $string" : " .*\(.\).*") &&
  printf '"%s" has "%s" (at least) more than once\n' "$string" "${c:-<newline>}"

Para obter um relatório de bytes duplicados, em um sistema GNU, você poderia fazer:

$ string=$'This is a string\nwith «multi-byte» «characters»\n'
printf %s "$string" | od -An -vtc -w1 | LC_ALL=C sort | LC_ALL=C uniq -dc
      5
      3    a
      2    c
      2    e
      3    h
      5    i
      3    r
      4    s
      5    t
      2   \n
      2  253
      2  273
      4  302

Os bytes fora do intervalo coberto por ASCII são representados como seu valor octal, os caracteres de controle com seu valor octal ou a representação \x C.

Para obter um relatório de caracteres :

$ printf %s "$string" | recode ..dump | sort | uniq -dc
      2 000A   LF    line feed (lf)
      5 0020   SP    space
      3 0061   a     latin small letter a
      2 0063   c     latin small letter c
      2 0065   e     latin small letter e
      3 0068   h     latin small letter h
      5 0069   i     latin small letter i
      3 0072   r     latin small letter r
      4 0073   s     latin small letter s
      5 0074   t     latin small letter t
      2 00AB   <<    left-pointing double angle quotation mark
      2 00BB   >>    right-pointing double angle quotation mark

Observe, entretanto, que recode não sabe sobre todos os caracteres Unicode (especialmente os recentes).

    
por 13.12.2015 / 14:58