echo 212334123434test233abc44 |
awk '{gsub("[^0-9]+","\n"); print;}' |
awk '{ if (length($0) > max) {max = length($0); maxline = $0} }
END { print maxline }'
212334123434
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.
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.
$ 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
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.
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
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
Uma solução em perl
:
echo 212334123434test233abc44 |
perl -nle 'print ((
map { $_->[0] }
sort{ $a->[1] <=> $b->[1] }
map { [$_,length] }
split /\D+/, $_)[-1]
)'
212334123434
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)
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
.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. 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
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
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
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
Tags text-processing awk sed