CS50P PS2化妆板如何使str中的中间字母无效

问题描述 投票:0回答:3

我正在为 CS50P 制作 PS2,但遇到了困难,需要一些帮助。以下是代码的条件:

在哈佛大学所在地马萨诸塞州,可以要求 您的汽车的个性车牌,带有您选择的字母和 数字而不是随机数字。不过,其中的要求包括:

  • “所有梳妆台必须至少以两个字母开头。”

  • “……个性牌最多可包含 6 个字符(字母或数字)并且 至少 2 个字符。”

  • “盘子中间不能使用数字;他们必须在最后到来。例如,AAA222 将是可接受的……虚荣板; AAA22A 是不可接受的。使用的第一个数字不能是 ‘0’。”

  • “不允许使用句号、空格或标点符号。”

我的一切功能都正常,除非它在 str 中间有字母(在我的代码中为

s
),例如
FE43E2
应该输出无效,但当前输出有效。我应该如何实施?

这是我当前的代码:

`

def main():
    plate = input("Plate: ")
    if is_valid(plate):
        print("Valid")
    else:
        print("Invalid")
def is_valid(s):
    if 2 <= len(s) <= 6 and s.isalnum():
        if s[0].isalpha() and s[1].isalpha():
            if s[-1].isdecimal():
                for char in s[2:]:
                    if char.isdecimal():
                        has_number = True
                        if char.isalpha() and has_number:
                            print("Has letters in the middle")
                            return False
                        elif char != "0":
                            print("No leading 0")
                            return True
                        else:
                            print("Leading 0")
                            return False
                else:
                    print("First two characters are letters")
                    return True
            else:
                print("Doesn't end with a number")
                return False
        else:
            print("First two characters arent letters")
            return False
    else:
        print("Length of isn't between 2 and 6 characters")
        return False
main()

我目前试图判断 s 的前 2 个字符之后是否有任何字符是数字,那么如果 s 中还有一个字母则返回 False,因此无效。

python loops cs50
3个回答
1
投票

我认为如果您使用非常简单的状态机而不是深度嵌套的

if
语句,问题会变得更容易解决。比如:

import pytest


def is_valid(plate) -> bool:
    # vanity plates may contain a maximum of 6 characters
    # and a minimum of 2 characters
    if len(plate) < 2 or len(plate) > 6:
        return False

    state = 0
    for i, c in enumerate(plate):
        # vanity plates may contain...letters or numbers
        # No periods, spaces, or punctuation marks are allowed
        if not (c.isdecimal() or c.isalpha()):
            return False

        if state == 0:
            # All vanity plates must start with at least two letters
            if c.isdecimal():
                return False
            if i == 1:
                state = 1
        elif state == 1:
            # If we find a number, everything else needs to be numbers
            if c.isdigit():
                # First number used cannot be '0'
                if c == "0":
                    return False
                state = 2
        elif state == 2:
            # Letters after numbers is not allowed
            if c.isalpha():
                return False

    return True

我们可以使用 pytest 添加一个简单的测试套件来验证事情是否按预期工作:

@pytest.mark.parametrize(
    "plate,valid",
    (
        ("A", False),  # Too short
        ("111111", False),  # Does not start with letters
        ("22AAAA", False),  # Does not start with letters
        ("AA..AA", False),  # Contains non-alphanumerics
        ("AA22AA", False),  # Numbers cannot be in middle
        ("AA0000", False),  # The first number used cannot be 0
        ("A22222", False),  # Must start with two letters
        ("AAAAAAA", False),  # Too long
        ("aaaaaaa", False),  # Letters must be uppercase
        ("AA", True),
        ("AA2222", True),
        ("AAAAAA", True),
    ),
)
def test_is_valid(plate, valid):
    assert is_valid(plate) == valid

使用

pytest -v
运行这些测试会产生:

test_plates.py::test_is_valid[A-False] PASSED
test_plates.py::test_is_valid[111111-False] PASSED
test_plates.py::test_is_valid[22AAAA-False] PASSED
test_plates.py::test_is_valid[AA..AA-False] PASSED
test_plates.py::test_is_valid[AA22AA-False] PASSED
test_plates.py::test_is_valid[AA0000-False] PASSED
test_plates.py::test_is_valid[A22222-False] PASSED
test_plates.py::test_is_valid[AAAAAAA-False] PASSED
test_plates.py::test_is_valid[aaaaaaa-False] PASSED
test_plates.py::test_is_valid[AAAAAA\xd1-False] PASSED
test_plates.py::test_is_valid[AA-True] PASSED
test_plates.py::test_is_valid[AA2222-True] PASSED
test_plates.py::test_is_valid[AAAAAA-True] PASSED

我在上面的代码中使用

isalpha()
来测试字母。这可以说是错误的;虽然法规中没有明确规定,但我怀疑:

  • 字母必须大写
  • 字母只能是A-Z的英文字母

正如所写,像

lower
NIÑO
SCHÖN
这样的词是有效的车牌。如果您喜欢不同的行为,您可以替换:

        if not (c.isdecimal() or c.isalpha()):
            return False

与:

        if not (c.isdecimal() or c in string.ascii_uppercase):
            return False

0
投票

我喜欢@larsks状态机答案,我鼓励您查看它。状态机可以使非常复杂的流程变得微不足道。

由于“提示”提供了使用

str
方法和切片的建议,让我们看看是否可以使用它们与更简单的状态机形成一个简单的解决方案,该状态机仅跟踪我们是否看到了数字。

请注意,这不会接近 @larsks 答案的性能,因为我们可能会多次评估整个字符串,但一旦您理解了它以及

found_a_number
的工作原理,您就可以在他们的答案中逐渐使用
state

def is_valid(plate):
    ## -----------------
    ## maximum of 6 characters and minimum of 2 characters
    ## -----------------
    if not (2 <= len(plate) <= 6):
        return False
    ## -----------------

    ## -----------------
    ## No periods, spaces, or punctuation marks
    ## -----------------
    if not plate.isalnum():
        return False
    ## -----------------

    ## -----------------
    ## must start with at least two letters.
    ## -----------------
    if not plate[:2].isalpha():
        return False
    ## -----------------

    ## -----------------
    ## Deal with numbers
    ## -----------------
    found_a_number = False
    for character in plate[2:]:
        ## -----------------
        ## first number used cannot be a "0"
        ## -----------------
        if character == "0" and not found_a_number:
            return False
        ## -----------------

        ## -----------------
        ## letters cannot appear after numbers
        ## -----------------
        if character.isdigit():
            found_a_number = True
        elif found_a_number:
            return False
        ## -----------------
    ## -----------------

    ## -----------------
    ## It must have been good
    ## -----------------
    return True
    ## -----------------

def test_plate(plate):
    return plate, is_valid(plate)

print(test_plate("AAA222"))
print(test_plate("FE43E2"))

这应该给你:

('AAA222', True)
('FE43E2', False)

0
投票

尝试您的代码,嵌套的“if”语句似乎与您的问题中指出的规则不符。似乎需要的是提示输入车牌号,然后按照所述进行简单的测试(有效的最小/最大长度,前两个字符是字母,并且没有嵌入数字)。以下是该程序的重构版本。

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

def is_valid(s):
    numchar = False

    if len(s) < 2 or len(s) > 6:
        print("Invalid length - less than two or greater than six")
        return False

    if not s[0].isalpha() or not s[1].isalpha():
        print("First two characters are not alpha")
        return False

    x = range(len(s))

    for n in x:
        if s[n].isdigit():  # Numeric character is encountered
            if s[n] == '0' and not numchar: # First encountered digit cannot be zero
                print("Initial digit may not be zero")
                return False
            numchar = True 
        if s[n].isalpha():  # Alpha character encountered - check to see if any previous character is digit
            if numchar:
                print("Embedded numeric characters are not allowed")
                return False

    print("Entered plate code is valid")    # If this point is reached, the plate code is valid
    return True
    
main()

测试各种车牌样本,包括您的条目(FE43E2),似乎会产生适当的终端输出。

craig@Vera:~/Python_Programs/Plates$ python3 License.py 
Plate: FE43E2
Embedded numeric characters are not allowed
Invalid
craig@Vera:~/Python_Programs/Plates$ python3 License.py 
Plate: D 
Invalid length - less than two or greater than six
Invalid
craig@Vera:~/Python_Programs/Plates$ python3 License.py 
Plate: D34444
First two characters are not alpha
Invalid
craig@Vera:~/Python_Programs/Plates$ python3 License.py 
Plate: DDW345
Entered plate code is valid
Valid

为了解决评论中提到的其他有效性要求,以下是对不允许初始数字为零的附加测试。

craig@Vera:~/Python_Programs/Plates$ python3 License.py 
Plate: AA0234
Initial digit may not be zero
Invalid

这里的要点是,有时需要嵌套测试,但尝试确定简单的串行测试是否会提供所需的结果。

© www.soinside.com 2019 - 2024. All rights reserved.