Bir dizedeki en uzun sayıyı nasıl yazdırabilirim?


11

Bir dizede en uzun sayıyı yazdırmak için bir yöntem arıyorum.

Örneğin: Dizgim varsa

212334123434test233

nasıl yazdırabilirim

212334123434

?

Not: Sayısal olarak daha yüksek değer için değil, en uzun sürekli sayı dizisini arıyorum.


Düzenleme: Cevaplar için teşekkürler, herkes. Bu sorunun cevabı oldukça ezici oldu. @ HaukeLaging'in gönderisini kabul edilen cevap olarak işaretledim çünkü özel durumuma çok iyi uyuyordu, ancak tüm cevapların eşit derecede geçerli olduğunu belirtmek istiyorum. Bir sorunu çözmek için birkaç farklı seçeneğe sahip olmak her zaman harikadır.


Eşit derecede uzun sürekli diziler olduğunda yöntemin ne yapmasını istersiniz? İlkini al? Son? Rastgele mi?
Anthon

@Hanhon Huh, bunu düşünmemiştim. Neyse ki bu benim özel durumumda bir sorun değil. Sanırım seçeneklerden herhangi biri iyi olurdu.
29.04.2014

3
Kabul ettiğiniz cevabın (ve şimdiye kadar biri hariç ) ondalık sayılarla ilgilenmeyeceğini unutmayın. Bunun sizin için bir sorun olup olmadığını bilmiyorum.
terdon

@terdon: Özel durumumda bir sorun değil çünkü gerçek sayılar yerine kimliklerle uğraşıyorum ama yine de cevabınız için teşekkür etmek istiyorum! Eminim başka biri bunu çok faydalı bulacaktır.
Nisan'ta Glutanimate

Çözümün negatif sayılarla başa çıkmasını ister misiniz? Ve eğer öyleyse - eksi işareti uzunluğa doğru sayılır mı?
Floris

Yanıtlar:


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

212334123434

13

Ben sadece ile yapabilirsiniz inanıyoruz grep, sortve tailde. İşte bazı örnek dizeler.

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

<str>Soru dizimiz nerede .

Misal

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

Şimdi bunları komutum aracılığıyla çalıştırırsam grep ....

$ 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

Bu yaklaşım, basamak dizisi olan tüm alt dizeleri seçerek çalışır. Daha sonra bu çıktıyı sayısal olarak sıralarız sort -nve ardından kullanarak listedeki son değeri alırız tail -1. Bu en uzun alt dize olacaktır.

tail -1Örneklerden birini alıp yeniden çalıştırarak nasıl çalıştığını görebilirsiniz :

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

Sıfırlarla başlayan dizeler

Yukarıdaki yaklaşım, biri dışında kavrayabildiğim her durum için işe yarar. @terdon , yukarıdaki yaklaşımı engelleyen bu senaryoyu sohbette belirtti .

  • 0000000000001
  • 2

Bu yüzden bununla başa çıkmak için taktikleri biraz değiştirmeniz gerekir. Yukarıdaki yaklaşımın çekirdeği hala kullanılabilir, ancak sonuçlara karakter sayısını da eklememiz gerekir. Bu sıralama sonuçlarını dizelerdeki karakterlerin sayısına ve değerlerine göre sıralama yeteneğini verir.

$ 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

Sonuçlar:

$ 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

Bash'in bir değişkenin uzunluğunu belirleme yeteneğini kullanarak bunu biraz yoğunlaştırabilirsiniz ${#var}.

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

`Grep -P'yi kullanma

grep -P ...Yukarıda kullanmayı tercih ettim çünkü Perl geliştiricisi olarak sınıfın sözdizimi gibi tüm basamakları söyleme gibi: veya \d+yerine . Ancak bu özel sorun için gerçekten gerekli değildir. Bu şekilde kullandığım gibi kolayca değiştirebilirsiniz :[[:digit:]]\+[0-9]\+grep

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

Örneğin:

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

2
Kullanılması ${#i}dize uzunluğunu almak için aradığınız kaydedebilirsiniz wcEğer bash-özgü gitmek isterseniz,
Glenn Jackman

@glennjackman - teşekkürler benim A 8- iyileştirme eklendi)
slm

GNU grep 2.16 (en azından) -P'nin "oldukça deneysel" olduğunu söylüyor. Bunun grep -o "[0-9]\+"yerine kullanabilirsinizgrep -oP "\d+"
David Conrad

1
@DavidConrad - Bu ayrıntıları A'ya da ekledik, teşekkürler!
slm

8

Bir çözüm perl:

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

Referanslar


2
Güzel bir Schwartz dönüşümünü sev!
glenn jackman

7

Komut satırında geçirilen dize ile python kullanma ve maksimum uzunluktaki ilk diziyi istediğinizi varsayarsak:

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)

2
veya python -c "import re,sys; print max(re.split(r'\D+', sys.argv[1]), key=len)"
tersely

7

İşte ondalıklarla ve tamsayılarla başa çıkabilen başka bir Perl yaklaşımı:

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

Şimdiye kadar gönderilen cevapların hiçbirinin ondalık sayılarla ilgilenmeyeceğini ve sayısal olarak en büyük sayıyı değil, en uzununu istediğinizi belirttiğiniz için, aslında ondalık sayılara ihtiyacınız olduğunu varsayıyorum .

açıklama

  • perl -lne: -n"Girdi satır satır okuma ve -eüzerinde verilen komut dosyasını çalıştırma" anlamına gelir . -lHer bir yeni satır ekler printçağrısı (ve diğer şeyler burada ilgili değildir).
  • while(/([\d.]+)/g): tüm sayılar arasında yineleme ( \danlamına gelir [0-9], böylece [\d.]rakamlar eşleşir ve .. Negatif sayılar bulmak istiyorsanız, ekleyin -. Parantezler $1, bir sonraki adımda kullanılan eşleşen dizeyi yakalar .
  • $max=$1 if length($1) > length($max): Geçerli maçın uzunluğu şu ana kadarki en uzun süreden büyükse ( $max) maçı kaydedin $max.
  • print $max: bulunan en uzun sayı dizesini yazdırır. Bu , while döngüsü bittikten sonra çalıştırılacaktır , bu nedenle tüm sayılar bulunduktan sonra.

1
+1 Normal ifadeniz biraz fazla genel. Örneğin IP adresleriyle eşleşir. Bunun \D(\d+(?:\.\d+)?)\Dyerine böyle bir şey öneriyorum .
Joseph R.

Ayrıca \Dçapa olmadan çalışmak gerekir ...
Joseph R.

@JosephR. hmm, doğru, .IP adreslerinde olduğu gibi art arda düşünmemiştim .
terdon

6

verilmiş

str="212334123434test233"

sonra bash

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

Dizideki rakam olmayan karakterleri boşluk yerine boşlukla değiştirerek oluşturulmuş bir dizi kullanan muhtemelen daha saf bir bash çözümü

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

4

@Mikeserv'in cevabına dayanarak, başka bir alternatif daha var. Sayıları çıkarır (mikeserv'in yöntemine göre), sonra sayı sırasına göre sıralar ve sonuncuyu alır. Baştaki sıfırları engellemeniz, bu size en büyük sayıyı verecektir (işareti dikkate almaz):

echo 1111askdlfm2234 |  printf %s\\n $(tr -sc 0-9 \ ) | sort -n | tail -1

Bu aslında işe yarıyor - benim olmadı. Yanlış tarafta 'r' vardı! Onu sileceğim. Ayrıca - gibi kabukları da kullanabilirsiniz -set -- $(echo $str | tr ... ) ; b=${#1} ; for d ; do [ ${#d} -gt $b ] && b=${#d} n=$d ; done ; echo $n
mikeserv

1
Kendi korkunç görevimi sildim ve sen benimle yeterince ilgilendin. Zaten zaten kullandığınız triçin, yukarıdakileri dahil ettiyseniz kin getirmezdim. Muhtemelen sort daha hızlıdır, ancak, yine, akışın. İle aynı şekilde bitmesini bekler $(subshell). Bilmiyorum. Her durumda, seninki zaten mükemmel bir cevap, ama yukarıdaki kabuk döngüsüne eklemek istiyorsanız, özgür olduğumu söylüyorum. Ve bu arada - sortküçük bir yaratıcı işlemle wc -Lve teeakışta tamamen olmadan yapabilmeniz mümkündür ... Bu soruyla işim bitti - utanıyorum.
mikeserv

Son bir şey olsa da - tralt kabuktan da çekilip kurtulmanız gerekebilir printf. Sadece yap '0-9' '\n'.
mikeserv

@mikeserv - bu site hakkında iyi olan şey, birbirimizden öğrenmemiz. Yardım ettiğin için teşekkür ederim; Cevabınız olmasaydı kendi başıma bile başlamazdım ...
Floris

2

bash ve GNU sıralama

IFS=$'\0' read -r l _ < <(tr -cs '[:digit:]' '[\0*]' <<<'11abcde1234556ghijk22'| sort -znr)
echo $l
1234556

2

Dizeyi bölmek için sayısal olmayan karakterler kullanın ve üçlü bir işleçle en uzun diziyi veya en büyük sayısal değeri (eşit uzunlukta sayılar için) bulun.

$ 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

Awk'ın kayıt ayırıcısını ( RS) sayısal olmayan herhangi bir karakter dizesi olarak da ayarlayabilirsiniz :

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

2
Neden sadece RS = '[^0-9]+'Awk'un içsel döngüsünü ayarlayıp kullanmıyorsunuz? echo "212334123434test233" | awk -v RS='[^0-9]+' 'length(longest) < length($0) {longest = $0};END{print longest}' 212334123434

@awk_FTW bunu bir cevap olarak da yazmalısınız. :) Bana RSdeğişkeni gösterdiğiniz için teşekkürler , bunu ilk gördüğümde itiraf etmeliyim. Sen sunabileceği daha fazla ipucu var awkben hahaha yapmak daha!
hjk
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.