使用多个 if 条件时如何克服 ValueError?

How to overcome a ValueError when working with multiple if conditions?

我正在尝试制作一个可以识别文件夹名称是否为项目的脚本。为此,我想使用多个 if 条件。但是我努力应对来自检查的结果 ValueError,例如,文件夹名称的第一个字母以及它是否为数字。如果它是一个字符串,我想跳过该文件夹并让它检查下一个。预先感谢大家的帮助。 干杯,本

我试过 While 和 except ValueError: 但没有成功。

# 正确的项目名称 "YYMM_ProjectName" = "1908_Sample_Project"

projectnames = ['190511_Waldfee', 'Mountain_Shooting_Test', '1806_Coffe_Prime_Now', '180410_Fotos', '191110', '1901_Rollercoaster_Vision_Ride', 'Musicvideo_LA', '1_Project_Win', '19_Wrong_Project', '1903_di_2', '1907_DL_2', '3401_CAR_Wagon']

#检查条件

for projectname in projectnames:
    if int(str(projectname[0])) < 3 and int(projectname[1]) > 5 and ((int(projectname[2]) * 10) + int(projectname[3])) <= 12 and str(projectname[4]) == "_" and projectname[5].isupper():
        print('Real Project')
        print('%s is a real Project' % projectname)
        # print("Skipped Folders")

ValueError:以 10 为底的 int() 的无效文字:'E'

一个解决方案是创建一个快速函数来捕获错误和 returns false:

def isInt(elem):
    try:
        int(elem)
        return True
    except ValueError:
        return False
...

if all(isInt(e) for e in projectname[:3]) and int(str(projectname[0])) < 3 and ...:
    ...

或者您可以先使用 str.isdigit() 之类的东西作为检查,而不是编写您自己的函数,以避免首先触发 ValueError。


虽然如果我是你,我会重新考虑为什么你首先需要这么长且冗长的 if 声明。可能有更有效的方法来实现此功能。

根据我对所有 ifs 的理解...您实际上最好使用 regex 匹配。您正在解析每个字符,并期望每个字符都在非常有限的字符范围内。

我没有测试过这个模式字符串,所以它可能不正确或者需要根据您的需要进行调整。

import re

projectnames = ['1911_Waldfee', "1908_Project_Test", "1912_WinterProject", "1702_Stockfootage", "1805_Branded_Content"]

p = ''.join(["^", # Start of string being matched
             "[0-2]", # First character a number 0 through 2 (less than 3)
             "[6-9]", # Second character a number 6 through 9 (single digit greater than 5)
             "(0(?=[0-9])|1(?=[0-2]))", # (lookahead) A 0 followed only by any number 0 through 9 **OR** A 1 followed only by any number 0 through 2
             "((?<=0)[1-9]|(?<=1)[0-2])", # (lookbehind) Match 1-9 if the preceding character was a 0, match 0-2 if the preceding was a 1
             "_", # Next char is a "_"
             "[A-Z]", #Next char (only) is an upper A through Z
              ".*$" # Match anything until end of string 
    ])

for projectname in projectnames:
    if re.match(p, projectname):
        #print('Real Project')
        print('%s is a real Project' % projectname)
        # print("Skipped Folders")

编辑:========================

您可以使用以下方法逐步测试模式...

projectname = "2612_UPPER"
p = "^[0-2].*$" # The first character is between 0 through 2, and anything else afterwards
if re.match(p, projectname): print(projectname) 
# If you get a print, the first character match is right.
# Now do the next
p = "^[0-2][6-9].*$" # The first character is between 0 through 2, the second between 6 and 9, and anything else afterwards
if re.match(p, projectname): print(projectname) 
# If you get a print, the first and second character match is right.
# continue with the third, fourth, etc. 

您可以编写一个小型解析器(诚然,可能有点过头了):

from parsimonious.grammar import Grammar
from parsimonious.nodes import NodeVisitor
from parsimonious.exceptions import ParseError

projectnames = ['190511_Waldfee', 'Mountain_Shooting_Test', '1806_Coffe_Prime_Now', '180410_Fotos', '191110', '1901_Rollercoaster_Vision_Ride', 'Musicvideo_LA', '1_Project_Win', '19_Wrong_Project', '1903_di_2', '1907_DL_2', '3401_CAR_Wagon']

class ProjectVisitor(NodeVisitor):
    grammar = Grammar(
        r"""
        expr    = first second third fourth fifth rest
        first   = ~"[0-2]"
        second  = ~"[6-9]"
        third   = ~"\d{2}"
        fourth  = "_"
        fifth   = ~"[A-Z]"
        rest    = ~".*"
        """
    )

    def generic_visit(self, node, visited_children):
        return visited_children or node

    def visit_third(self, node, visited_children):
        x, y = int(node.text[0]), int(node.text[1])
        if not (x * 10 + y) <= 12:
            raise ParseError

# loop over them
pv = ProjectVisitor()
for projectname in projectnames:
    try:
        pv.parse(projectname)
        print("Valid project name: {}".format(projectname))
    except ParseError:
        pass

这会产生

Valid project name: 1806_Coffe_Prime_Now
Valid project name: 1901_Rollercoaster_Vision_Ride
Valid project name: 1907_DL_2

这是完成工作的方法,可能不是最有效的方法。

鉴于您的项目列表,

projectnames = [
    '190511_Waldfee', 
    'Mountain_Shooting_Test', 
    '1806_Coffe_Prime_Now', 
    '180410_Fotos', 
    '191110', 
    '1901_Rollercoaster_Vision_Ride', 
    'Musicvideo_LA', 
    '1_Project_Win', 
    '19_Wrong_Project', 
    '1903_di_2', 
    '1907_DL_2', 
    '3401_CAR_Wagon'
    ]

我看到有效的 YYMM 字符串数量有限(更准确地说是 24 个)。所以我首先创建了一个包含这 24 个有效 YYMM 的列表。

nineteen = list(range(1900, 1913))
eighteen = list(range(1800, 1813))
YYMM = nineteen + eighteen    # A list of all 24 valid dates

然后我使用 try-except-else 块稍微修改你的 for 循环,

for projectname in projectnames:

    try:
        first_4_digits = int(projectname[:4])  # Make sure the first 4 are digits.
    except ValueError:
        pass  # Pass silently
    else:
        if (first_4_digits in YYMM
            and projectname[4] == "_"
            and projectname[5].isupper()):
            # if all conditions are true
            print("%s is a real project." % projectname)