Извлечение положительных/отрицательных чисел с плавающей запятой из строки

Вопрос или проблема

Я пытаюсь извлечь числа из некоторого текста. В настоящее время я использую следующее:

echo "2.5 test. test -50.8" | tr '\n' ' ' | sed -e 's/[^0-9.]/ /g' -e 's/^ *//g' -e 's/ *$//g' | tr -s ' '

Это даст мне 2.5, “.” и 50.8. Как мне изменить первый sed, чтобы он обнаруживал дробные числа, как положительные, так и отрицательные?

grep хорошо справляется с этой задачей:

$ echo "2.5 test. test -50.8" | grep -Eo '[+-]?[0-9]+([.][0-9]+)?'
2.5
-50.8

Как это работает

  • -E

    Используйте расширенные регулярные выражения.

  • -o

    Возвращает только совпадения, а не контекст

  • [+-]?[0-9]+([.][0-9]+)?+

    Сопоставляет числа, которые определяются как:

    • [+-]?

      Необязательный ведущий знак

    • [0-9]+

      Одно или несколько чисел

    • ([.][0-9]+)?

      Необязательная точка, за которой следует одно или несколько чисел.

Получение вывода в одной строке

$ echo "2.5 test. test -50.8" | grep -Eo '[+-]?[0-9]+([.][0-9]+)?' | tr '\n' ' '; echo ""
2.5 -50.8

Решение с grep:

$ echo "2.5 test. test -50.8" | tr ' ' '\n' | grep -E '^[+-]?[0-9]*\.?([0-9]+)$'
2.5
-50.8
  • tr просто преобразует строку в несколько строк, заменяя пробелы на символы новой строки.

  • Команда grep ищет строки, которые начинаются с необязательного + или -, возможно, за которыми следуют некоторые цифры и необязательная десятичная точка. Затем мы требуем некоторые цифры в конце.

00000123.91288000, что выглядит странно. Это число, которое мы хотим отфильтровать или нет? Это технически дробное число, просто странно отформатированное.

ИЗМЕНИТЕ: Чтобы правильно проверять числа, не пишите свое собственное регулярное выражение! Используйте библиотечную рутину из надежного источника.

В моем случае я бы использовал пакет Perl Scalar::Util, который имеет удобную подпрограмму looks_like_number():

$ echo "2.5 test. test -50.8" | tr ' ' '\n' | perl -MScalar::Util -ne 'Scalar::Util::looks_like_number($_) && print'
2.5
-50.8

Это имеет дополнительное преимущество в обнаружении чисел в других формах, таких как 1e3.

Довольно много людей описали, как извлечь дробные числа из текста.

В течение моих поисков ответ от @John1024 произвел наибольшее впечатление.

Существует довольно много решений ‘jq’ по поводу сортировки результатов, когда дробные числа фактически являются семантически версионированными числами. Например, 1.10.1 больше, чем 1.2.0 …

В конце концов, я написал короткий сценарий программы с интерфейсом CLI, который может работать как отдельная программа или встраиваться.

floatversion -M "$(curl -sf "https://github.com/TuxVinyards/floatversion/releases" | grep 's/tag')"
1.0.0

floatversion -r "$(curl -sf https://github.com/qemu/qemu/tags | grep 's/tag')"
9.1.1  9.1.0  9.0.3  8.2.7  7.2.14  

floatversion -M "$(curl -sf https://github.com/qemu/qemu/tags | grep 's/tag')"
9.1.1
  floatversion --options  "quoted-input-source"

  Извлекает числа, разделенные точками, или семантические номера версий с необязательными суффиксами,
  и другие общие вариации из данной строки или текстового файла

  -h | --help         показать помощь 
  -V | --version      показать версию
  -c | --col          показать список в виде колонки вместо строки (если не -M)
  -r | --rev          показать список в обратном порядке  
  -a | --all          показать все извлеченные значения, а не только уникальные 
  -n | --num          сортировать по стандартным номерам, а не по версиям
  -f | --full         проверить наличие дополнительных сем. вер. суффиксов, например -beta
  -F | --filter       содержит данные элементы -F  "строка  строка  строка" 
  -S | --starts       начинается с -S  "строка  строка  строка" 
  -D | --delete       не содержит: -D  "строка  строка  строка" 
  -M | --max          выводит наибольшее/последнее значение в списке, только, с '-r' показывает наименьшее/самое раннее
  -g | --gt           A > B, возвращает true/false -g "A B" (.nums или сем. вер, для -lt используйте B A)
  -v | --verbose      для вывода проблем показывать последовательности алгоритма (только полная версия) 
       --sort-v       использовать сортировку -V (если она доступна) предпочтительно к методам jq по умолчанию
       --no-svb       без возврата к 'jq', если 'sort -V' недоступен, показывать ошибку вместо

  Без параметров создает одну отсортированную строку всех уникальных найденных элементов
  Фильтрует вывод как строку, колонку или максимум. После вывода grep требует колонок.

  Тесты показывают, что методы сортировки 'jq' более надежны, чем 'sort -V', особенно с алфа-суффиксами
  Во всех случаях возвращает false, если ничего нет

На GitHub здесь

Ответ или решение

Извлечение положительных и отрицательных чисел с плавающей запятой из строки — это задача, с которой сталкиваются многие программисты и пользователи, работающие с текстовыми данными. В этой статье мы рассмотрим различные подходы к решению этой проблемы, используя утилиты командной строки, такие как grep и sed, а также более мощные инструменты, такие как Perl.

Понимание проблемы

Нам необходимо извлечь числа, которые могут быть как положительными, так и отрицательными, например, «2.5» и «-50.8» из строки «2.5 test test -50.8». Важно также учитывать формат чисел с плавающей запятой и обеспечить корректное извлечение без лишних символов.

Решение с использованием grep

Одним из простых и эффективных способов является использование утилиты grep с расширенными регулярными выражениями. Вот команда, которая помогает извлекать нужные числа:

echo "2.5 test test -50.8" | grep -Eo '[+-]?[0-9]+([.][0-9]+)?'

Как это работает

  • -E: Опция для использования расширенных регулярных выражений.
  • -o: Возвращает только совпадения, исключая контекст.
  • [+-]?: Опциональный знак (плюс или минус).
  • [0-9]+: Одна или более цифр перед десятичной точкой.
  • ([.][0-9]+)?: Опциональная десятичная точка, за которой следует одна или более цифр.

Эта команда успешно извлечет «2.5» и «-50.8», исключая лишние символы.

Устранение лишних символов и форматирование вывода

Если вам необходимо отформатировать результат так, чтобы все числа выводились в одной строке, вы можете использовать следующую команду:

echo "2.5 test test -50.8" | grep -Eo '[+-]?[0-9]+([.][0-9]+)?' | tr '\n' ' '; echo ""

Это преобразует полученные числа в строку, разделяя числа пробелами.

Решение с использованием sed

Другой подход — использование sed. Однако, чтобы эффективно извлекать числа с плавающей запятой, выражение будет несколько сложнее:

echo "2.5 test test -50.8" | sed -n 's/.*\([+-]*[0-9]*\.[0-9]*\).*/\1/p'

Этот метод может потребовать более тщательной настройки, чтобы правильно обрабатывать все возможные форматы чисел.

Оптимальное решение с использованием Perl

Использование Perl — это более надежный и универсальный способ проверки чисел, особенно если ваши данные могут содержать более сложные форматы, такие как научная нотация:

echo "2.5 test test -50.8" | tr ' ' '\n' | perl -MScalar::Util -ne 'Scalar::Util::looks_like_number($_) && print'

Преимущества использования Perl

  • Возможность работы с более сложными форматами чисел, такими как научная нотация (например, 1e3).
  • Более точная проверка на предмет того, является ли строка числом без необходимости ручной настройки регулярных выражений.

Заключение

Извлечение чисел с плавающей запятой из строки может выполняться различными способами, в зависимости от ваших требований и доступных инструментов. Использование grep скорее подойдет для простых задач, в то время как Perl предложит вам большую гибкость и возможности для работы с более сложными данными. Выбор подхода зависит от вашего конкретного приложения и характера данных, с которыми необходимо работать.

Оцените материал
Добавить комментарий

Капча загружается...