编辑:我编辑了一个问题来纠正一个重大错误(遗憾的是,到目前为止提供的所有答案都无效):命令行可以在单词之间包含空格,所以没有解决方法基于使用空格作为标记之间的分隔符及其参数将起作用!我在原帖中对这一遗漏深表歉意。
我有一个包含简单(假设)命令语言命令的文本文件,如下所示:
$BOOLEAN_COMMAND
$NUMERIC COMMAND ALPHA 1 3 6 9 10
$NUMERIC COMMAND BETA
2 7 9 10 15
25 40 900 2000
$NUMERIC COMMAND GAMMA 6 9 11
1)每个“COMMAND”以一个特殊字符('$')开头,后跟一个数字序列(“命令参数”)。
2)没有参数的命令被认为是“布尔命令”,默认情况下假设值为True。
3)可以有许多带参数的命令(我在这里将它们称为“Alpha”,“Beta”等),但无论它们的名称如何,都会跟随一行包含参数的一行。
4)包含命令的行之间可能有或没有空行。
我编写了一个函数,它读取包含所述命令和参数的文件,并仅返回特定命令的参数(作为函数参数传递)。这是:
def get_params(fname, command):
fspecs = open(fname,"r")
params = []
for cline in fspecs:
cline = cline.strip()
if not cline:
continue # Blank line
if cline.startswith('$'):
if command in cline:
params = cline.partition(command)[-1].split()
#else: # Continuation of a command.
# params.append(cline)
fspecs.close()
if len(params) == 0: # Boolean command, defaults to True
ret_val = True
else:
ret_val = ' '.join(params) # Numeric command, gets parameters
return ret_val
p = get_params('command_file', '$BOOLEAN COMMAND')
print p # returns True
p = get_params('command_file', '$NUMERIC COMMAND ALPHA')
print p # returns 1 3 6 9 10
p = get_params('command_file', '$NUMERIC COMMAND BETA')
print p # should return 2 7 9 10 15, but returns True
当给定命令的参数在一行(紧接在命令令牌之后)时,上述代码有效,但当参数在后续行中时失败(在这种情况下,它只返回'True',因为没有参数在命令令牌后找到)。如果'else'子句没有被注释掉,它只需要包含任何令牌参数的所有行,直到文件的末尾。实际运行上面的代码将更好地证明问题。
我想要的是能够读取一个特定的令牌(传递给该函数)并获取其参数,无论它们是否延伸到多行或者命令文件中可能有多少个其他令牌。
答案 0 :(得分:2)
由于命令可能需要多行,因此更容易不按换行拆分文本文件。我建议按' $'分拆。代替。
此示例代码有效:
def get_params(fname, desired_command):
with open(fname,"r") as f:
content = f.read()
for element in content.split('$'):
element = element.replace('\n', ' ').strip()
if not element:
continue
if ' ' in element:
command, result = element.split(' ', 1)
else:
command, result = element, True
if desired_command == command or desired_command == '${}'.format(command):
return result
这是我的编辑,它适用于包含命令的空格:
import re
COMMAND_RE = re.compile('([A-Z_ ]+[A-Z]) ?(.+)? *')
def get_params(fname, desired_command):
with open(fname,"r") as f:
content = f.read()
for element in content.split('$'):
element = element.replace('\n', ' ').strip()
if not element:
continue
command, result = COMMAND_RE.search(element).groups()
if desired_command == command or desired_command == '${}'.format(command):
return result or True
答案 1 :(得分:1)
这是我的方法:根据空白(空格,制表符和新行)拆分所有内容。然后构造一个字典,命令名称作为键,参数作为值。从该字典中,您可以查找任何命令的参数。此方法仅打开和读取文件一次:
from collections import deque
def parse_commands_file(filename):
with open(filename) as f:
tokens = deque(f.read().split())
command2parameters = dict()
while tokens:
command_name = tokens.popleft()
# Added
while tokens and tokens[0].isalpha() and not tokens[0].startswith('$'):
command_name = command_name + ' ' + tokens.popleft()
# end added
parameters = []
while tokens and not tokens[0].startswith('$'):
parameters.append(int(tokens.popleft()))
command2parameters[command_name] = parameters or True
return command2parameters
if __name__ == '__main__':
command = parse_commands_file('commands.txt')
print '$BOOLEAN_COMMAND:', command.get('$BOOLEAN_COMMAND')
print '$NUMERIC_COMMAND_ALPHA:', command.get('$NUMERIC_COMMAND_ALPHA')
print '$NUMERIC_COMMAND_BETA:', command.get('$NUMERIC_COMMAND_BETA')
输出:
$BOOLEAN_COMMAND: True
$NUMERIC_COMMAND_ALPHA: [1, 3, 6, 9, 10]
$NUMERIC_COMMAND_BETA: [2, 7, 9, 10, 15, 25, 40, 900, 2000]
deque
数据结构,代表双端队列。这种结构的行为类似于列表,但在插入和从两端弹出方面效率更高int
,您可以将它们转换为浮动或保留它们parameters or True
基本上说:如果参数为空,请使用True
,否则请保留我添加了一个补丁来处理名称中带空格的命令。但是,此解决方案只是一个补丁,如果您有多个空格,它不起作用,如:
$MY COMMAND HERE
在这种情况下,多个空格被压缩成一个。
答案 2 :(得分:1)
这是另一种解决方案。这个使用正则表达式,它不会在命令中挤压多个空格:
import re
def parse_commands_file(filename):
command_pattern = r"""
(\$[A-Z _]+)* # The command, optional
([0-9 \n]+)* # The parameter which might span multiple lines, optional
"""
command_pattern = re.compile(command_pattern, flags=re.VERBOSE)
with open(filename) as f:
tokens = re.findall(command_pattern, f.read())
return {cmd.strip(): [int(n) for n in params.split()] for cmd, params in tokens}
if __name__ == '__main__':
command = parse_commands_file('commands.txt')
print '$BOOLEAN_COMMAND:', command.get('$BOOLEAN_COMMAND')
print '$NUMERIC COMMAND ALPHA:', command.get('$NUMERIC COMMAND ALPHA')
print '$NUMERIC COMMAND BETA:', command.get('$NUMERIC COMMAND BETA')
基本上,命令模式表示每行可能包含命令名和数字参数两部分,两者都是可选的。
请注意,命令可能包含尾随空格,这就是我们使用表达式cmd.strip()
将其删除的原因。
此外,re.findall()
返回的参数部分需要通过空格分隔它们来解析,然后使用表达式int
转换为[int(n) for n in params.split()]