Maya/Python - 循环遍历文本文件的函数,除了某些行
Maya/Python - function which loops though text file except for some lines
我在这里和那里找到了一些答案,但我想不出构建我想要的东西的确切方法。如果您能提供帮助,请提前致谢。
我有多个文本文件,它们都是以相同的方式构建的,但每个文件中的信息不同。我想遍历每个文件并逐行 return 其中的信息。另一方面,我有一些布尔值定义是否必须跳过文件中的特定行。例如:"if boolean1 is true and lineInTheCorrespondingFile = 40, then skip that line, else, read it but skip line 36 and 37 instead".
问题是我不知道如何进行,因为函数知道打开了哪个文件 and 读取了哪一行 and如果它必须跳过它或不。知道我需要在函数末尾 return 独立编辑每一行。
到目前为止,这是我的代码:
def locatorsDatas (self):
preset = cmds.optionMenu ("presetMenu", q = 1, v = 1)
rawFile = presetsDir + preset.lower() + ".txt"
with open(rawFile) as file:
file.seek (0)
for lineNum, line in enumerate(file, start = 1):
if lineNum > 8 : # Skip header
locator = eval (line)
locName = locator[0]
xVal = locator[1]
yVal = locator[2]
zVal = locator[3]
locScale = locator[4]
locColor = locator[5]
if locator == "":
break
return (locName, xVal, yVal, zVal, locScale, locColor)
我不知道我应该将什么值传递给函数以使其跳过我想要的行,因为我知道我不能将它直接写入其中,因为每个文件都不会在同一行中断。
哦,它只有 return 文件的一行而不是每一行。
希望说清楚了,能帮帮我,再次感谢。
我发现你的代码有很多问题。
首先,您总是return处理第 8 行的数据,而不是任何其他数据。如果您有许多要从文件中提取的值,您可能希望使用 yield
语句而不是 return
使您的函数成为生成器。然后调用代码可以使用 for
循环访问数据或将生成器传递给 list
或接受任何可迭代的另一个函数。
def locatorsDatas(self):
# ...
lineNum, line in enumerate(file, start=1):
# ...
yield results
如果你不能使用生成器但需要你的函数来 return 连续的行,你需要将文件迭代器(或者也许 enumerate
环绕它的迭代器)保存在某处在函数范围之外。这意味着您不需要在每次调用该函数时都重新打开文件。你可以这样做:
def __init__(self):
preset = cmds.optionMenu ("presetMenu", q = 1, v = 1)
rawFile = presetsDir + preset.lower() + ".txt"
self.preset_file_enumerator = enumerate(open(rawFile)) # save the iterator on self
def locatorsDatas(self):
try:
lineNum, line = next(self.preset_file_enumerator) # get a value from the iterator
# do your processing
return results
except StopIteration:
# do whatever is appropriate when there's no more data in the file here
raise ValueError("no more data") # such as raising an exception
我看到的下一个问题是如何处理每一行以获取单独的数据。你正在使用 eval
如果你正在处理的数据被轻微委托的话,这是一个非常糟糕的主意。那是因为 eval
将其参数解释为 Python 代码。它可以任何事情,包括从您的硬盘中删除文件!更安全的版本是 ast.literal_eval
,它只允许字符串包含 Python 文字(包括列表、字典和集合,但不包括变量查找、函数调用或其他更复杂的代码)。
你还有一个错误检查,我认为它不会按照你的意图进行。 if locator == ""
测试可能放置得太晚,以避免前面的行从 eval
行提取数据时出错。而 break
声明 运行 将导致函数退出,而不会再 returning 任何东西。如果你只是想跳过空行,你应该把检查放在循环的顶部并使用 continue
而不是 break
.
现在我们终于可以解决您在问题标题中提出的问题。如果您想根据各种标志跳过某些行,您只需要在循环时检查这些标志并执行 continue
以跳过您不想阅读的行。我不完全理解你问的关于如何传递标志的问题,但假设你可以将它们作为参数提供,下面是代码的外观草图:
def locatorsDatas(self, skip_40=False, skip_50=True):
# open file, ...
for lineNum, line in enumerate(file, start = 1):
if (not line or
lineNum < 8 or
skip_40 and lineNum == 40 or
skip_50 and lineNum == 50):
continue
# parse the line
yield result
显然,您应该使用自己的标志名称和逻辑,而不是我为示例代码编写的名称和逻辑。如果您的逻辑更复杂,您可能更喜欢为每个标志使用单独的 if
语句,而不是像我那样将它们全部打包到一个单独的条件中。
我在这里和那里找到了一些答案,但我想不出构建我想要的东西的确切方法。如果您能提供帮助,请提前致谢。
我有多个文本文件,它们都是以相同的方式构建的,但每个文件中的信息不同。我想遍历每个文件并逐行 return 其中的信息。另一方面,我有一些布尔值定义是否必须跳过文件中的特定行。例如:"if boolean1 is true and lineInTheCorrespondingFile = 40, then skip that line, else, read it but skip line 36 and 37 instead".
问题是我不知道如何进行,因为函数知道打开了哪个文件 and 读取了哪一行 and如果它必须跳过它或不。知道我需要在函数末尾 return 独立编辑每一行。
到目前为止,这是我的代码:
def locatorsDatas (self):
preset = cmds.optionMenu ("presetMenu", q = 1, v = 1)
rawFile = presetsDir + preset.lower() + ".txt"
with open(rawFile) as file:
file.seek (0)
for lineNum, line in enumerate(file, start = 1):
if lineNum > 8 : # Skip header
locator = eval (line)
locName = locator[0]
xVal = locator[1]
yVal = locator[2]
zVal = locator[3]
locScale = locator[4]
locColor = locator[5]
if locator == "":
break
return (locName, xVal, yVal, zVal, locScale, locColor)
我不知道我应该将什么值传递给函数以使其跳过我想要的行,因为我知道我不能将它直接写入其中,因为每个文件都不会在同一行中断。 哦,它只有 return 文件的一行而不是每一行。
希望说清楚了,能帮帮我,再次感谢。
我发现你的代码有很多问题。
首先,您总是return处理第 8 行的数据,而不是任何其他数据。如果您有许多要从文件中提取的值,您可能希望使用 yield
语句而不是 return
使您的函数成为生成器。然后调用代码可以使用 for
循环访问数据或将生成器传递给 list
或接受任何可迭代的另一个函数。
def locatorsDatas(self):
# ...
lineNum, line in enumerate(file, start=1):
# ...
yield results
如果你不能使用生成器但需要你的函数来 return 连续的行,你需要将文件迭代器(或者也许 enumerate
环绕它的迭代器)保存在某处在函数范围之外。这意味着您不需要在每次调用该函数时都重新打开文件。你可以这样做:
def __init__(self):
preset = cmds.optionMenu ("presetMenu", q = 1, v = 1)
rawFile = presetsDir + preset.lower() + ".txt"
self.preset_file_enumerator = enumerate(open(rawFile)) # save the iterator on self
def locatorsDatas(self):
try:
lineNum, line = next(self.preset_file_enumerator) # get a value from the iterator
# do your processing
return results
except StopIteration:
# do whatever is appropriate when there's no more data in the file here
raise ValueError("no more data") # such as raising an exception
我看到的下一个问题是如何处理每一行以获取单独的数据。你正在使用 eval
如果你正在处理的数据被轻微委托的话,这是一个非常糟糕的主意。那是因为 eval
将其参数解释为 Python 代码。它可以任何事情,包括从您的硬盘中删除文件!更安全的版本是 ast.literal_eval
,它只允许字符串包含 Python 文字(包括列表、字典和集合,但不包括变量查找、函数调用或其他更复杂的代码)。
你还有一个错误检查,我认为它不会按照你的意图进行。 if locator == ""
测试可能放置得太晚,以避免前面的行从 eval
行提取数据时出错。而 break
声明 运行 将导致函数退出,而不会再 returning 任何东西。如果你只是想跳过空行,你应该把检查放在循环的顶部并使用 continue
而不是 break
.
现在我们终于可以解决您在问题标题中提出的问题。如果您想根据各种标志跳过某些行,您只需要在循环时检查这些标志并执行 continue
以跳过您不想阅读的行。我不完全理解你问的关于如何传递标志的问题,但假设你可以将它们作为参数提供,下面是代码的外观草图:
def locatorsDatas(self, skip_40=False, skip_50=True):
# open file, ...
for lineNum, line in enumerate(file, start = 1):
if (not line or
lineNum < 8 or
skip_40 and lineNum == 40 or
skip_50 and lineNum == 50):
continue
# parse the line
yield result
显然,您应该使用自己的标志名称和逻辑,而不是我为示例代码编写的名称和逻辑。如果您的逻辑更复杂,您可能更喜欢为每个标志使用单独的 if
语句,而不是像我那样将它们全部打包到一个单独的条件中。