特定的数据值未能产生我所期望的答案。

huangapple go评论62阅读模式
英文:

A particular data value does not yield the answer i was expecting

问题

这是一个用于检查车牌号条件的程序:

  1. 所有个性化车牌号必须以至少两个字母开头。
  2. 个性化车牌号最多可以包含6个字符(字母或数字),最少要有2个字符。
  3. 数字不能出现在车牌号的中间,必须出现在末尾。例如,AAA222是一个合格的个性化车牌号;AAA22A是不合格的。第一个数字不能是'0'。
  4. 不允许使用句点、空格或标点符号。

当我输入'PK40'时,它输出'invalid',但应该输出'valid',我做错了什么?

这是我的代码:

def main():
    plate = input("Plate: ")
    if is_valid(plate):
        print("Valid")
    else:
        print("Invalid")


def is_valid(s):
    if check_length(s) and start_with_letters(s) and zero_check(s) and no_punctuation(s):
        return True
    else:
        return False


def check_length(s):
    if 2 <= len(s) < 7:
        return True
    else:
        return False


def start_with_letters(s):
    if s[0:2].isalpha():
        return True
    else:
        return False


def zero_check(s):
    index = 0
    while index < len(s):
        if not s[index].isalpha():
            if s[index] == "0":
                return False
            else:
                break
        index += 1


def no_punctuation(s):
    i = 2
    punctuation = 0
    while i < len(s) and punctuation == 0:
        char = s[i]
        if not char.isalpha():
            if not char.isdigit():
                punctuation += 1
        i += 1

    if punctuation == 0:
        return True
    else:
        return False


main()

请注意,我已经修复了一些代码中的错误,并将一些冗余的条件检查简化为更紧凑的形式。希望这个修复后的代码可以正确判断车牌号是否有效。

英文:

This is a program that is supposed to check following conditions for a number plates:

  1. All vanity plates must start with at least two letters.
  2. vanity plates may contain a maximum of 6 characters (letters or numbers) and a minimum of 2 characters.
  3. Numbers cannot be used in the middle of a plate; they must come at the end. For example, AAA222 would be an acceptable vanity plate; AAA22A would not be acceptable. The first number used cannot be a ‘0’.
  4. No periods, spaces, or punctuation marks are allowed.

Now, when I enter 'PK40' it yields 'invalid' but it is supposed to print 'valid' what am i doing wrong?

this is my code:

def main():
    plate = input(&quot;Plate: &quot;)
    if is_valid(plate):
        print(&quot;Valid&quot;)
    else:
        print(&quot;Invalid&quot;)


def is_valid(s):
    check_length(s)
    if check_length(s):
        start_with_letters(s)
        if start_with_letters(s):
            zero_check(s)
            if zero_check(s):
                no_punctuation(s)
                if no_punctuation(s):
                    return True
                else:
                    return False
            else:
                return False
        else:
            return False
    else:
        return False


def check_length(str):
    if len(str)&gt;= 2 and len(str)&lt; 7:
        return True
    else:
        return False

def start_with_letters(str1):
    if str1[0:2].isalpha():
        return True
    else:
        return False

def zero_check(str2):
    index = 0
    while index &lt; len(str2):         #inedx starts from 0 but len starts from 1, thus &#39;less than&#39;
        if str2[index].isalpha() == False:    #AAA23A returns false at index = 3
            if str2[index] == &quot;0&quot;:
                return False
            else:
                break          #because there is no 0 in the string
        index = index + 1

def no_punctuation(str3):
    i = 2
    punctuation = 0
    while i &lt; len(str3) and punctuation == 0:
        char = str3[i]
        if char.isalpha() == False:          #if no alphabet is found, check for numbers
            if char.isdigit() == False:       #no digits
                punctuation += 1
        i =+ 1

    if punctuation == 0:
        return True
    else:
        return False

main()

答案1

得分: 1

  1. zero_check方法在成功的情况下没有返回一个真值。它有一个默认返回None,这被计算为False。你想要的是:
def zero_check(str2):
    index = 0
    while index < len(str2):  # index从0开始,但len从1开始,因此应该是'小于'
        if str2[index].isalpha() == False:  # AAA23A在索引3处返回False
            if str2[index] == "0":
                return False
            else:
                break  # 因为字符串中没有0
        index = index + 1
    return True
  1. no_punctuation调用i =+ 1(即i = +1i = 1),而应该是i += 1
def no_punctuation(str3):
    i = 2
    punctuation = 0
    while i < len(str3) and punctuation == 0:
        char = str3[i]
        if char.isalpha() == False:  # 如果没有字母,则检查数字
            if char.isdigit() == False:  # 没有数字
                punctuation += 1
        i += 1

    if punctuation == 0:
        return True
    else:
        return False

一些改进。isalphaisdigit可能会产生误导。例如:

>>> "⑴".isdigit()
True
>>> "à".isalpha()
True

在这些情况下,更加细致的检查会更安全:

def is_letter(c):
    return "A" <= c <= "Z"

def is_number(c):
    return "0" <= c <= "9"

进一步说,我建议将你列出的每种情况分解为各自的方法。你还可以使用for c in s:的语法来更清晰地迭代字符串。你的主要is_valid方法可以简单地将所有调用的结果组合在一起:

def main():
    plate = input("Plate: ")
    if is_valid(plate):
        print("Valid")
    else:
        print("Invalid")

def is_valid(s):
    return (
        correct_length(s)
        and two_letter_start(s)
        and no_letters_after_numbers(s)
        and all_letters_or_numbers(s)
    )

def correct_length(s):
    """
    Vanity plates may contain a maximum of 6 characters (letters or numbers) and a minimum of 2 characters.
    """
    return 2 <= len(s) <= 6

def two_letter_start(s):
    """
    All vanity plates must start with at least two letters.
    """
    return is_letter(s[0]) and is_letter(s[1])

def no_letters_after_numbers(s):
    """
    Numbers cannot be used in the middle of a plate; they must come at the end.
    For example, AAA222 would be an acceptable vanity plate; AAA22A would not be acceptable.
    The first number used cannot be a ‘0’.
    """
    number_found = False
    for c in s:
        if not number_found:
            # The first number used cannot be a ‘0’.
            if c == "0":
                return False
            if is_number(c):
                number_found = True
        else:
            # Numbers cannot be used in the middle of a plate
            if is_letter(c):
                return False
    return True

def all_letters_or_numbers(s):
    """
    No periods, spaces, or punctuation marks are allowed.
    """
    for c in s:
        if not (is_letter(c) or is_number(c)):
            return False
    return True

def is_letter(c):
    return "A" <= c <= "Z"

def is_number(c):
    return "0" <= c <= "9"

if __name__ == "__main__":
    main()

最后,使用正则表达式,你可以将其简化为一行:

import re

def main():
    plate = input("Plate: ")
    if is_valid(plate):
        print("Valid")
    else:
        print("Invalid")

def is_valid(s):
    return re.match(r"^(?=[A-Z0-9]{2,6}$)[A-Z]{2}[A-Z]*([1-9][0-9]*)?$", s)

分解:

^                   字符串的开始
(?=                 前瞻以便我们可以断定额外的条件
    [A-Z0-9]{2,6}   将包含2-6个字母或数字
    $               然后字符串将结束
)
[A-Z]{2}            前两个字符是字母
[A-Z]*              后面可以有更多的字母
(
  [1-9]             如果有数字它们以1-9开头
  [0-9]*            然后我们可以有任意数量的0-9数字
)?                  数字是可选的
$                   字符串然后结束
英文:
  1. the zero_check method does not return a truthy value in the success case. It has a default return of None which evaluates to False. You want:
def zero_check(str2):
    index = 0
    while index &lt; len(str2):         #inedx starts from 0 but len starts from 1, thus &#39;less than&#39;
        if str2[index].isalpha() == False:    #AAA23A returns false at index = 3
            if str2[index] == &quot;0&quot;:
                return False
            else:
                break          #because there is no 0 in the string
        index = index + 1
    return True
  1. no_punctuation calls i =+ 1 (i.e. i = +1 or i = 1) when it should be i += 1
def no_punctuation(str3):
    i = 2
    punctuation = 0
    while i &lt; len(str3) and punctuation == 0:
        char = str3[i]
        if char.isalpha() == False:          #if no alphabet is found, check for numbers
            if char.isdigit() == False:       #no digits
                punctuation += 1
        i += 1

    if punctuation == 0:
        return True
    else:
        return False

Some improvements. isalpha and isdigit can be very misleading. For example:

&gt;&gt;&gt; &quot;⑴&quot;.isdigit()
True
&gt;&gt;&gt; &quot;&#224;&quot;.isalpha()
True

Its better to be more granular in these cases. Using the range of ascii values would be safer:

def is_letter(c):
    return &quot;A&quot; &lt;= c &lt;= &quot;Z&quot;

def is_number(c):
    return &quot;0&quot; &lt;= c &lt;= &quot;9&quot;

Going further, I would break down each case you listed into their own method. You can also iterate through a string with the syntax for c in s: which will make this much cleaner. Your main is_valid method can simply combine the results of all calls together:

def main():
    plate = input(&quot;Plate: &quot;)
    if is_valid(plate):
        print(&quot;Valid&quot;)
    else:
        print(&quot;Invalid&quot;)


def is_valid(s):
    return (
        correct_length(s)
        and two_letter_start(s)
        and no_letters_after_numbers(s)
        and all_letters_or_numbers(s)
    )


def correct_length(s):
    &quot;&quot;&quot;
    Vanity plates may contain a maximum of 6 characters (letters or numbers) and a minimum of 2 characters.
    &quot;&quot;&quot;
    return 2 &lt;= len(s) &lt;= 6


def two_letter_start(s):
    &quot;&quot;&quot;
    All vanity plates must start with at least two letters.
    &quot;&quot;&quot;
    return is_letter(s[0]) and is_letter(s[1])


def no_letters_after_numbers(s):
    &quot;&quot;&quot;
    Numbers cannot be used in the middle of a plate; they must come at the end.
    For example, AAA222 would be an acceptable vanity plate; AAA22A would not be acceptable.
    The first number used cannot be a ‘0’.
    &quot;&quot;&quot;
    number_found = False
    for c in s:
        if not number_found:
            # The first number used cannot be a ‘0’.
            if c == &quot;0&quot;:
                return False
            if is_number(c):
                number_found = True
        else:
            # Numbers cannot be used in the middle of a plate
            if is_letter(c):
                return False
    return True


def all_letters_or_numbers(s):
    &quot;&quot;&quot;
    No periods, spaces, or punctuation marks are allowed.
    &quot;&quot;&quot;
    for c in s:
        if not (is_letter(c) or is_number(c)):
            return False
    return True


def is_letter(c):
    return &quot;A&quot; &lt;= c &lt;= &quot;Z&quot;


def is_number(c):
    return &quot;0&quot; &lt;= c &lt;= &quot;9&quot;


if __name__ == &quot;__main__&quot;:
    main()

Finally, using a regex, you can make this a one-liner:

import re


def main():
    plate = input(&quot;Plate: &quot;)
    if is_valid(plate):
        print(&quot;Valid&quot;)
    else:
        print(&quot;Invalid&quot;)


def is_valid(s):
    return re.match(r&quot;^(?=[A-Z0-9]{2,6}$)[A-Z]{2}[A-Z]*([1-9][0-9]*)?$&quot;, s)

Breakdown:

^                   Start of the string.
(?=                 Lookahead so we can assert an extra condition.
    [A-Z0-9]{2,6}   There will 2-6 letters or numbers.
    $               Then the string will end.
)
[A-Z]{2}            The first two characters are letters.
[A-Z]*              There can be more letters to follow.
(
  [1-9]             If there are numbers, they start with 1-9
  [0-9]*            Then we can have any amount of 0-9 digits
)?                  The digits are optional.
$                   Then the string ends.

huangapple
  • 本文由 发表于 2023年6月8日 11:38:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76428465.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定