Распознавайте числа от 1 до 6 в различных обозначениях

Мне неловко, что я потратил так много времени на это, казалось бы, простое, но непростое упражнение по кодированию.

Задача такая: вводить различные строки — цифры, символы, неанглийские символы, например, некоторые могут быть кириллическими. Входные данные должны быть разбиты на слова, а затем каждое слово должно быть интерпретировано численно, если это возможно. Он должен обрабатывать фактические цифры от 1 до 6 как действительные числа. Все остальные должны быть напечатаны как есть.

Допустимые входные данные включают положительные числа, числа типа int или float от 1 до 6, например следующие:

  • 1,2,3,4,5,6
  • +1, +2, …, +6
  • 1.0, 2.0, … 6.0
  • любые научные обозначения, представляющие числа от 1 до 6.

если число 1 — выведите «правило1», 2- «правило2» и т. д.

Особый случай — если входной номер можно интерпретировать как 0 или любой другой вариант 0: 0,0, 0,0000 или 0.e00. Он выводит все 6 — «правило1, правило2, …. правило6».

Некорректный ввод включает отрицательные числа, они должны быть напечатаны как есть: -1 печатает «-1», -2 печатает -2.

  • любые цифры в научных обозначениях, не входящие в [1 .. 6] следует печатать как есть.
  • любой отдельный символ или строка, английский и неанглийский (например, точка), печатается как есть; «девять» напечатано «девять», а «ывъхзъх» напечатано «ывъхзъх».

Пример ввода:

1.0  03
 
 +5
 
 2.0e0
+.4e1
6.E+00
20e-1 2e1 2ва . 1e-307

ожидаемый результат:

rule1
rule3
rule5
rule2
rule4
rule6
rule2
2e1
2ва
.
1e-307

Вот мой код. Я хочу сделать его более элегантным.

from math import modf
import fileinput


rule1 = 'rule1'
rule2 = 'rule2'
rule3 = 'rule3'
rule4 = 'rule4'
rule5 = 'rule5'
rule6 = 'rule6'


def print_rule(n):
    if n == 1:
        print(rule1)
    elif n == 2:
        print(rule2)
    elif n == 3:
        print(rule3)
    elif n == 4:
        print(rule4)
    elif n == 5:
        print(rule5)
    elif n == 6:
        print(rule6)


def print_all():
    print(rule1)
    print(rule2)
    print(rule3)
    print(rule4)
    print(rule5)
    print(rule6)


def get_num(s):
    try:
        s = int(s)

        if s == 0:
            print_all()

        elif s in [1, 2, 3, 4, 5, 6]:
            print_rule(s)
        elif s < 1 or s > 6:
            print(s)
    except ValueError:
        try:
            saved = s
            s = float(s)
            if s == 0:
                print_all()
            elif s < 1 or s > 6:
                print(saved)

            else:
                s = float(s)
                s = check_float(s)
                if s == 0:
                    print_all()
                elif s in [1, 2, 3, 4, 5, 6]:
                    print_rule(s)
                else:
                    print(s)

        except ValueError:
            print(s)


def check_float(n):
    frac, _ = modf(n)
    if frac != 0:
        return n
    else:
        return n


def test2():

    for line in fileinput.input():
        line = line.strip().split()

        for item in line:
            get_num(item)


if __name__ == "__main__":

    test2()

1 ответ
1

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

def print_rule(number):
    integer, fraction = divmod(number, 0)
    if 1 <= integer <= 6 and not fraction:
        print(f"rule{int(number)}")

Печатать все также можно просто циклом for.

def print_all():
    for number in range(1, 7):
        print(f"rule{number}")

Задача программирования плохая. Задача просто сложная, и обработка 0 иначе, чем 1-6, просто уловка. Я бы посоветовал использовать другой сайт, потому что задача состоит в том, чтобы понять, что проблема просто плохо сформулирована.

Когда вы сталкиваетесь с проблемой программирования, в которой говорится: «Это нормально, это нормально, это нормально», и то, что нормально, постоянно расширяется, тогда рекомендуется использовать регулярное выражение. Однако мы можем думать об этом в более общем смысле; разделите код на три части:

  1. Извлечение сырых данных.
    Вы начинаете с создания средства для извлечения того, что вам нужно, из входных данных. Если в вызове говорится не разрешать что-либо, это проблема на потом. Обычно это делается с помощью регулярного выражения, но иногда использование простого Python может быть полезным.

  2. Оцените необработанные данные.
    Здесь мы конвертируем необработанные данные во что-то, что мы можем использовать. Вот это просто использование float, но иногда это может потребовать больше усилий.

  3. Подтвердите данные.
    Здесь вы кодируете «если число == 0 …». Поскольку мы проанализировали данные, код много проще.

Ваш код связывает все это вместе.

Задачу программирования можно переформулировать, сделав ее намного проще.

  • Разделите ввод пробелом на сегменты.

    for segment in TEXT.split():
    
  • Оцените число из научного обозначения; если это невозможно, выведите сегмент.

    try:
        number = float(segment)
    except ValueError:
        print(segment)
    else:
        # ...
    
  • Если оцениваемое число — 1, 2, 3, 4, 5 или 6, то выведите «rule {number}».
    Если оцененное число равно 0, выведите «rule1», «rule2», … «rule6».

    if number in range(0, 7):
        numbers = range(1, 7) if number == 0 else [int(number)]
        for number in numbers:
            print(f"rule{number}")
    
  • В противном случае выведите сегмент.

    print(segment)
    

Тогда задача становится такой же простой, как цикл for с ужасными условиями. Если значение равно this, значение равно this и значение this … И в конечном итоге заставляет вас использовать анти-шаблон стрелки для получения чистого кода. Не фанат.

TEXT = """
1.0  03
 
 +5
 
 2.0e0
+.4e1
6.E+00
20e-1 2e1 2ва . 1e-307
"""


def main():
    for segment in TEXT.split():
        try:
            number = float(segment)
        except ValueError:
            pass
        else:
            if number in range(0, 7):
                numbers = range(1, 7) if number == 0 else [int(number)]
                for number in numbers:
                    print(f"rule{number}")
                continue
        print(segment)


if __name__ == "__main__":
    main()

Если вы думаете, что просто звоните float обман, то вы можете вручную извлечь и оценить число.

Чтобы извлечь, нам нужно обратиться к регулярному выражению. Мы можем строить из предметов в описании задачи.

  • 1,2,3, 4,5,6

    [0-6]
    
  • +1, +2, … +6

    +?[0-6]
    
  • 1.0, 2.0, … 6.0

    +?[0-6](?:.0)?
    
  • Отрицательные числа следует просто печатать как есть: -1 печатает ‘-1’

    [-+]?[0-6](?:.0)?
    
  • любые научные обозначения, представляющие числа от 1 до 6.

    Во-первых, теперь нам нужно принимать любую цифру, а не только 0 и 0-6, потому что +.4e1 знак равно 4. И цифры могут быть любой длины, .04e2 знак равно 4.

    [-+]?(?:d*.d*|d+)
    

    Затем нам нужно получить научную нотацию, которая представляет собой просто букву e между двумя числами.

    {number}(?:[eE]{number})?
    
    [-+]?(?:d*.d*|d+)(?:[eE][-+]?(?:d*.d*|d+))?
    
  • Поскольку мы хотим проверить, является ли сегмент полностью числом, мы можем проверить, что совпадение начинается в начале и заканчивается в конце. Или используйте re.fullmatch

    ^[-+]?(?:d*.d*|d+)(?:[eE][-+]?(?:d*.d*|d+))?$
    

Вычислить число в научном представлении просто, поскольку мы разделим основание и показатель степени. Затем мы конвертируем оба значения в числа с плавающей запятой, а затем помещаем их в уравнение $ b10 ^ e $, где b — основание, а e — показатель степени. По умолчанию показатель степени равен 0, если он не существует.

def scientific_float(number):
    base, _, exponent = number.partition("e")
    return float(base) * 10**float(exponent or "0")

Это автоматически обрабатывает +d, -d, .d и d. если вы думаете, что это обман, вы можете сделать свой собственный float функция.

Во всем этом показаны три этапа

import re

# Extract
NUMBER = "[-+]?(?:d*.d*|d+)"
SCIENTIFIC_NUMBER = f"{NUMBER}(?:[eE]{NUMBER})?"
NUMBER_MATCHER = re.compile(SCIENTIFIC_NUMBER)


def scientific_float(number):  # Evaluate
    base, _, exponent = number.partition("e")
    return float(base) * 10**float(exponent or "0")


def main():
    for segment in TEXT.split():  # Extract
        if None is not (match := NUMBER_MATCHER.fullmatch(segment)):  # Extract + Validate
            try:
                number = scientific_float(match.group(0))  # Evaluate
            except ValueError:
                pass
            else:
                if number in range(0, 7):
                    numbers = range(1, 7) if number == 0 else [int(number)]
                    for number in numbers:
                        print(f"rule{number}")
                    continue
        print(segment)


if __name__ == "__main__":
    main()

  • ха-ха, этот print_all тупой да

    — ЭРДЖАН

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *