Як я можу надрукувати найдовший номер у рядку?


11

Я шукаю спосіб друкувати найдовше число в рядку.

Наприклад, якщо у мене є рядок

212334123434test233

як я можу надрукувати

212334123434

?

Примітка. Я шукаю найдовшу безперервну послідовність чисел, а не чисельно вищу величину.


Редагувати: Дякую за відповіді, всі. Відповідь на це запитання була досить приголомшливою. Я відзначив пост @ HaukeLaging як прийняту відповідь, оскільки він дуже добре відповідав моєму конкретному випадку, але я хотів би зазначити, що всі відповіді однаково справедливі. Завжди чудово мати кілька різних варіантів вирішення проблеми.


Що ви хочете зробити методом, коли є кілька однаково довгих безперервних послідовностей? Взяти перший? Останній? Випадковий?
Антон

@Anthon Huh, я не думав про це. На щастя, це не проблема в моєму конкретному випадку. Я думаю, будь-який з варіантів буде добре.
Глутанімат

3
Зауважте, що відповідь, яку ви прийняли (і всі інші поки що, крім однієї ), не стосуватиметься десяткових чисел. Я не знаю, чи це проблема для вас.
terdon

@terdon: Це не проблема в моєму конкретному випадку, оскільки я маю справу з ідентифікаторами, а не фактичними номерами, але все ж хочу подякувати за вашу відповідь! Я впевнений, що хтось інший вважатиме це дуже корисним у майбутньому.
Glutanimate

Чи хотіли б ви, щоб рішення могло мати справу з негативними числами? І якщо так - чи позначається знак мінус до довжини?
Флоріс

Відповіді:


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

212334123434

13

Я вважаю , що ви можете зробити це тільки з grep, sortі tailяк добре. Ось кілька прикладів рядків.

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

Де <str>знаходиться наша стаття?

Приклад

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

Тепер, якщо я запускаю їх через свою 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

Цей підхід працює, вибираючи всі підрядки, що є послідовностями цифр. Потім сортуємо цей вихід чисельно, sort -nа потім перебираємо останнє значення у списку, використовуючи tail -1. Це буде найдовша підрядка.

Ви можете бачити, як це працює, знімаючи tail -1і повторюючи один із прикладів:

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

Рядки, що починаються з нулів

Вищеописаний підхід працює в будь-якій ситуації, яку я міг уявити, крім однієї. @terdon згадував у чаті цей сценарій, який порушує вищезазначений підхід.

  • 0000000000001
  • 2

Тож для вирішення цього вам потрібно трохи змінити тактику. Ядро вищевказаного підходу все ще може бути використане, однак нам потрібно також ввести кількість символів у результати. Це дає можливість сортувати результати за сортуванням результатів за кількістю символів у рядках та їх значеннями.

$ 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

Результати:

$ 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 визначати довжину змінної, використовуючи ${#var}.

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

Використання `grep -P

Я вирішив використовувати grep -P ...вище, тому що я, будучи розробником Perl, люблю синтаксис класу говорити всі цифри так: \d+замість [[:digit:]]\+або [0-9]\+. Але для цієї конкретної проблеми вона насправді не потрібна. Ви можете так само легко замінити те, що grepя використовував так:

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

Наприклад:

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

2
Використання ${#i}для отримання довжини рядка може заощадити вам дзвінки wc, якщо ви хочете перейти на баш-специфіку
glenn jackman

@glennjackman - спасибі додали покращення моїм A 8-)
slm

GNU grep 2.16 (принаймні) говорить, що Р є "високо експериментальним". Ви можете використовувати grep -o "[0-9]\+"замістьgrep -oP "\d+"
Девід Конрад

1
@DavidConrad - додав ці деталі до A також, дякую!
slm


7

Використання python з рядком, переданим у командному рядку, і припускаючи, що ви хочете першу послідовність максимальної довжини:

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
або в python -c "import re,sys; print max(re.split(r'\D+', sys.argv[1]), key=len)"
термінах

7

Ось ще один підхід Perl, який може мати справу з десятковими знаками, а також цілими числами:

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

Зауважте, що жоден із опублікованих відповідей не стосується десяткових знаків, і оскільки ви вказуєте, що ви хочете найдовше, а не найбільше число, я вважаю, що вам дійсно потрібні десяткові числа.

Пояснення

  • perl -lne: Засіб -n"прочитайте рядок введення за рядком та запустіть сценарій, заданий -eна ньому". -lДодає новий рядок кожного printвиклику (і інші речі , що не мають відношення тут).
  • while(/([\d.]+)/g): повторіть усі числа ( \dзначить [0-9], так вони [\d.]будуть відповідати цифрам і .. Якщо ви також хочете знайти від'ємні числа, додайте -. В дужках фіксується відповідна рядок, $1яка використовується на наступному кроці.
  • $max=$1 if length($1) > length($max): Якщо довжина поточного матчу більша за найдовший досі ( $max), збережіть відповідність як $max.
  • print $max: вивести найдовший рядок знайдених чисел. Це буде виконано після закінчення циклу while, тому після того, як всі числа знайдені.

1
+1 Однак ваш регекс трохи надто загальний. Наприклад, це відповідатиме IP-адресам. Я пропоную \D(\d+(?:\.\d+)?)\Dнатомість щось подібне .
Джозеф Р.

Також слід працювати без \Dякірів ...
Джозеф Р.

@JosephR. хм, правда, я не вважав послідовним, .як у IP-адресах.
terdon

6

Дано

str="212334123434test233"

то в баш

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

Можливо більш чисте рішення bash з використанням масиву, побудованого за допомогою заміни нецифрових символів у рядку на пробіл, замість grep

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

4

Спираючись на відповідь @mikeserv, тут є ще одна альтернатива. Він витягує числа (за методом mikeserv), потім сортує їх у числовому порядку та бере останнє. Якщо заборонити провідні нулі, це дасть вам найбільшу кількість (не беручи до уваги знак):

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

Цей насправді працює - мій ні. У мене було неправильне значення "\ r"! Я збираюся її видалити. Ви також можете просто скористатися оболонкою типу -set -- $(echo $str | tr ... ) ; b=${#1} ; for d ; do [ ${#d} -gt $b ] && b=${#d} n=$d ; done ; echo $n
mikeserv

1
Я видалив власну жахливу публікацію, і ви досить обережно розібралися зі мною. Оскільки ви все trодно користуєтесь , я не зазнаю ніякої шкоди, якщо ви включили вище. Можливо, sort це швидше, але, знову ж таки, він чекає, коли потік закінчиться так само, як і $(subshell). Не знаю. У будь-якому випадку, ваше вже є чудовою відповіддю, але якщо ви відчуваєте, що додаєте до вищезгаданого циклу оболонки, не соромтесь - це все, що я говорю. І до речі - цілком можна обійтися без sortтворчого поводження wc -Lі teeв потоці ... Хоча я і з цим питанням закінчуюся - мені соромно.
mikeserv

І останнє, що все-таки - ви також можете витягнути trз підзору і позбутися printf. Просто роби '0-9' '\n'.
mikeserv

@mikeserv - хороша річ про цей сайт полягає в тому, що ми вчимося один у одного. Спасибі за вашу допомогу; без вашої відповіді я б навіть не почав самостійно ...
Флоріс,

2

bash і GNU сортування

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

2

Використовуйте нечислові символи, щоб розділити рядок і знайти найдовшу послідовність чи найбільше числове значення (для чисел з однаковою довжиною) з потрійним оператором.

$ 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 ( RS) як будь-який нечисловий рядок символів:

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

2
Чому б просто не встановити RS = '[^0-9]+'та використовувати притаманну петлю Awk? echo "212334123434test233" | awk -v RS='[^0-9]+' 'length(longest) < length($0) {longest = $0};END{print longest}' 212334123434

@awk_FTW вам слід також поставити це як відповідь. :) Дякую, що показали мені RSзмінну, мушу визнати, що це перший раз, коли я її бачу. У вас є більше пропозицій, awkніж я, ха-ха!
hjk
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.