Como posso imprimir o número mais longo em uma string?

11

Estou procurando um método para imprimir o número mais longo em uma string.

Por exemplo: se eu tiver a string

212334123434test233

como posso imprimir

212334123434

?

Nota: Estou procurando a sequência contínua mais longa de números, não para o valor numericamente mais alto.

Editar: Obrigado pelas respostas, todos. A resposta a essa pergunta foi bastante impressionante. Eu marquei o post do @HaukeLaging como a resposta aceita porque se adequava muito bem ao meu caso específico, mas gostaria de salientar que todas as respostas são igualmente válidas. É sempre bom ter várias opções diferentes para resolver um problema.

    
por Glutanimate 29.04.2014 / 03:57

9 respostas

7
echo 212334123434test233abc44 | 
awk '{gsub("[^0-9]+","\n"); print;}' | 
awk '{ if (length($0) > max) {max = length($0); maxline = $0} } 
  END { print maxline }'

212334123434
    
por 29.04.2014 / 04:27
13

Eu acredito que você pode fazer isso com apenas grep , sort e tail também. Aqui estão alguns exemplos de strings.

$ echo <str> | grep -oP "\d+" | sort -n | tail -1

Em que <str> é nossa string em questão.

Exemplo

$ set -o posix; set | grep "str[0-9]"
str0=212334123434test233
str1=212334123434test233abc44
str2=233test212334123434
str3=a212334123434test233abc44
str4=a91234b212334123434abc

Agora, se eu executar esses comandos por meio do meu comando grep ... , por sua vez.

$ echo $str0 | grep -oP "\d+" | sort -n | tail -1
212334123434
$ echo $str1 | grep -oP "\d+" | sort -n | tail -1
212334123434
$ echo $str2 | grep -oP "\d+" | sort -n | tail -1
212334123434
$ echo $str3 | grep -oP "\d+" | sort -n | tail -1
212334123434
$ echo $str4 | grep -oP "\d+" | sort -n | tail -1
212334123434

Essa abordagem funciona selecionando todas as subseqüências que são sequências de dígitos. Em seguida, classificamos essa saída numericamente, sort -n e, em seguida, pegamos o último valor na lista, usando tail -1 . Esta será a substring mais longa.

Você pode ver como funciona retirando tail -1 e executando novamente um dos exemplos:

$ echo $str4 | grep -oP "\d+" | sort -n
91234
212334123434

Strings que começam com zeros

A abordagem acima funciona para todas as situações que eu poderia conceber, exceto uma. @terdon mencionado no chat este cenário que frustra a abordagem acima.

  • 0000000000001
  • 2

Então, para lidar com isso, você precisará mudar um pouco as táticas. O kernel da abordagem acima ainda pode ser aproveitado, no entanto, precisamos injetar o número de caracteres nos resultados também. Isso dá ao sort a capacidade de classificar os resultados por número de caracteres nas strings & seus valores.

$ for i in $(echo $str0 | grep -oP "\d+");do a=$(echo "$i" | wc -c); \
    echo "$a $i"; done | sort -n | tail -1 | cut -d" " -f2

Resultados:

$ echo $str0
0000000000001a2test

$ for i in $(echo $str0 | grep -oP "\d+");do a=$(echo "$i" | wc -c); \
    echo "$a $i"; done | sort -n | tail -1 | cut -d" " -f2
0000000000001

Você pode condensar isso um pouco fazendo uso da capacidade do Bash de determinar o tamanho de uma variável usando ${#var} .

$ for i in $(echo $str0 | grep -oP "\d+");do echo "${#i} $i"; done | \
    sort -n | tail -1 | cut -d" " -f2
0000000000001

Usando o 'grep -P

Eu optei por usar grep -P ... acima porque eu, sendo um desenvolvedor de Perl, gosto da sintaxe de dizer todos os dígitos da seguinte forma: \d+ , em vez de [[:digit:]]\+ ou [0-9]\+ . Mas para este problema em particular, não é realmente necessário. Você pode facilmente trocar o grep que usei assim:

$ .... grep -o "[0-9]\+" ....

Por exemplo:

$ for i in $(echo $str0 | grep -o "[0-9]\+");do echo "${#i} $i"; done | \
    sort -n | tail -1 | cut -d" " -f2
0000000000001
    
por 29.04.2014 / 06:57
8

Uma solução em perl :

echo 212334123434test233abc44 |
perl -nle 'print ((
    map { $_->[0] }
    sort{ $a->[1] <=> $b->[1] }
    map { [$_,length] }
    split /\D+/, $_)[-1]
    )'
212334123434

Referências

por 29.04.2014 / 08:15
7

Usando python com a string passada na linha de comando e supondo que você queira a primeira seqüência de tamanho máximo:

import sys

longest = current = ""
for x in sys.argv[1]:
    if current and not x.isdigit():
        if len(current) > len(longest):
            longest = current
        current = ""
    else:
        current += x 
print(longest)
    
por 29.04.2014 / 06:42
7

Aqui está outra abordagem Perl que pode lidar com números decimais e inteiros:

echo "0.212334123434test233" | 
 perl -lne 'while(/([\d.]+)/g){$max=$1 if length($1) > length($max)} print $max'

Observe que nenhuma das respostas postadas até agora tratará de decimais e, desde que você especifique que deseja o número mais longo e não numericamente maior, presumo que você precise decimais

.

Explicação

  • perl -lne : O -n significa "leia a entrada linha por linha e execute o script dado por -e sobre ele". O -l adiciona uma nova linha a cada chamada print (e outras coisas não relevantes aqui).
  • while(/([\d.]+)/g) : iterar todos os números ( \d significa [0-9] , portanto [\d.] corresponderá a dígitos e . . Se você também quiser encontrar números negativos, adicione - . Os parênteses capturam a string correspondente como $1 , que é usado na próxima etapa.
  • $max=$1 if length($1) > length($max) : Se o comprimento da correspondência atual for maior que o maior até agora ( $max ), salve a correspondência como $max .
  • print $max : imprime a maior sequência de números encontrados. Isso será executado após o loop while terminar, assim que todos os números forem encontrados.
por 29.04.2014 / 12:19
6

Dado

str="212334123434test233"

depois no bash

max=""
while read num; do 
  (( ${#num} > ${#max} )) && max=$num
done < <(grep -Eo '[0-9]+' <<< "$str")
echo $max
212334123434

Uma solução bash possivelmente mais pura usando uma matriz construída substituindo caracteres não dígitos na string por espaço em branco, no lugar do grep

max=""
declare -a nums="${str//[^[:digit:]]/ }"
for num in ${nums[@]}; do 
  (( ${#num} > ${#max} )) && max=$num
done
echo $max
    
por 29.04.2014 / 04:44
4

Com base na resposta do @mikeserv, aqui está outra alternativa. Ele extrai os números (por método de mikeserv), então os ordena em ordem numérica e pega o último. Bloqueio de zeros à esquerda, isso lhe dará o maior número (não levando em conta o sinal):

echo 1111askdlfm2234 |  printf %s\n $(tr -sc 0-9 \ ) | sort -n | tail -1
    
por 29.04.2014 / 14:49
2

bash e classificação GNU

IFS=$'
IFS=$'%pre%' read -r l _ < <(tr -cs '[:digit:]' '[%pre%*]' <<<'11abcde1234556ghijk22'| sort -znr)
echo $l
1234556
' read -r l _ < <(tr -cs '[:digit:]' '[%pre%*]' <<<'11abcde1234556ghijk22'| sort -znr) echo $l 1234556
    
por 29.04.2014 / 18:54
2

Use caracteres não numéricos para dividir a string e localize a seqüência mais longa ou o maior valor numérico (para números de comprimento igual) com um operador ternário.

$ echo "212334123434test233" | awk -F'[^0-9]+' '{for(i=1;i<=NF;i++){m=length($i)>=length(m)||$i>m?$i:m}};END{print m}'
212334123434

Você também pode definir o separador de registro do awk ( RS ) como qualquer sequência de caracteres não numéricos:

$ echo "212334123434test233" \
    | awk -v RS='[^0-9]+' '
        length(longest) < length($0) {longest = $0};
        END{print longest}'
212334123434
    
por 29.04.2014 / 05:00