0

我想通过它修复一个函数我可以计算使用了多少次:(,),[,] 如果 ( 的计数等于 ) 的计数并且如果 [ 的计数等于 ] 那么我有有效的语法!

我的第一次-失望-尝试:

filename=input("Give a file name:")

def  parenthesis(filename):
    try:
        f=open(filename,'r')
    except (IOError):
        print("The file",filename,"does not exist!False! Try again!")
    else:
         while True:
            for line in filename:
                line=f.readline()
                if line=='(':
                     c1=line.count('(')
                elif line==')':
                     c2=line.count(')')
                elif line=='[':
                     c3=line.count('[')
                elif line==']':
                     c4=line.count(']')
                elif line=='':
                    break

                if c1==c2:
                     print("Line: Valid Syntax")
                elif c1!=c2:
                     print("Line: InValid Syntax")
                elif c3==c4:
                     print("Line: Valid Syntax")
                elif c3!=c4:
                     print("Line: InValid Syntax")
    finally:
        f.close()

parenthesis(filename)
4

7 回答 7

3

请原谅这个回复的长度。

如果我对您的理解正确,您希望对括号进行简单的语法检查以确保它们正确平衡。在您的问题中,您指定了一个基于简单计数的测试,但正如其他人指出的那样,这并没有捕捉到像“([)]”这样的东西。

我还想对您代码的其他方面提出一些建设性的批评。

首先,最好从命令行获取文件名,而不是提示输入。这样您就可以在开发程序时轻松地重复运行程序,而无需一直输入文件名。这是你的方式:

$ python foo.py
给出文件名:data
[一些输出]
$ python foo.py
给出一个文件名:data
[一些输出]
$ python foo.py
给出一个文件名:data
[一些输出]

每次都需要输入文件名。您无需多次输入命令即可运行该程序。第一次之后,您可以使用箭头键从 shell 的命令历史记录中获取它。如果你从命令行获取文件名,你可以这样做:

$ python foo.py testfile
[一些输出]
$ python foo.py testfile
[一些输出]
$ python foo.py testfile
[一些输出]

这样,当您第二次测试时,您不需要输入超过向上箭头和 Enter 键的内容。这是一个小小的便利,但很重要:当您开发软件时,即使是很小的事情也会开始烦人。就像你在长途跋涉时脚下的一大粒沙子:前几公里你甚至不会注意到它,但再走几公里后,你就会流血。

在 Python 中,要访问命令行参数,您需要 sys.argv列表。对您的程序的相关更改:

import sys
filename = sys.argv[1]

如果你确实想提示,你应该使用内置input函数以外的东西。它将用户键入的任何内容解释为 Python 表达式,这会导致各种问题。您可以使用sys.stdin.readline.

无论如何,我们现在已经将文件名安全地存储在filename变量中。是时候用它做点什么了。你的parentheses函数几乎可以做所有事情,经验表明这通常不是最好的做事方式。相反,每个函数都应该只做一件事,但要做好。

我建议您应该将实际打开和关闭文件的部分与实际计数分开。这将简化计数的逻辑,因为它不需要担心其余部分。在代码中:

import sys

def check_parentheses(f):
    pass # we'll come to this later

def main():
    filename = sys.argv[1]
    try:
        f = file(filename)
    except IOError:
        sys.stderr.write('Error: Cannot open file %s' % filename)
        sys.exit(1)
    check_parentheses(f)
    f.close()

main()

除了重新安排事情之外,我还改变了其他一些事情。首先,我将错误消息写入标准错误输出。这是执行此操作的正确方法,并且意味着 shell 用户重定向输出的意外更少。(如果这对您没有任何意义,请不要担心,暂时接受它。)

其次,如果出现错误,我会使用sys.exit(1). 这告诉启动程序的人它失败了。在 Unix shell 中,这使您可以执行以下操作:

if python foo.py inputfile
then
    echo "inputfile is OK!"
else
    echo "inputfile is BAD!"
fi

当然,shell 脚本可能会做一些比仅仅报告成功或失败更有趣的事情。例如,它可能会删除所有损坏的文件,或者给写这些文件的人发送电子邮件,要求他们修复它们。美妙之处在于编写检查程序的您不需要关心。您只需正确设置程序退出代码,并让编写 shell 脚本的人操心其余的事情。

下一步是实际读取文件的内容。这可以通过多种方式完成。最简单的方法是逐行执行,如下所示:

for line in f:
    # do something with the line

然后我们需要查看该行中的每个字符:

for line in f:
    for c in line:
        # do something with the character

我们现在已经准备好开始检查括号了。正如其他人所建议的那样,堆栈是合适的数据结构。堆栈基本上是一个列表(或数组),您可以在其中将项目添加到一端,然后以相反的顺序取出它们。把它想象成一堆硬币:你可以在顶部添加一枚硬币,你可以取出最上面的硬币,但你不能从中间或底部取出一个。

(嗯,你可以,如果你这样做,这是一个巧妙的把戏,但计算机是简单的野兽,会被魔术弄得心烦意乱。)

我们将使用 Python 列表作为堆栈。要添加一个项目,我们使用列表的append方法,要删除我们使用的pop方法。一个例子:

stack = list()
stack.append('(')
stack.append('[')
stack.pop() # this will return '['
stack.pop() # this will return '('

要查看堆栈中最顶层的项目,我们使用stack[-1](换句话说,列表中的最后一个项目)。

我们使用堆栈如下:当我们找到一个左括号('(')、方括号('[')或大括号('{')时,我们将它放入堆栈。当我们找到一个右括号时,我们检查栈顶的元素,并确保它与关闭的元素匹配。如果不是,我们打印一个错误。像这样:

def check_parentheses(f):
    stack = list()
    for line in f:
        for c in line:
            if c == '(' or c == '[' or c == '{':
                stack.append(c)
            elif c == ')':
                if stack[-1] != '(':
                    print 'Error: unmatched )'
                else:
                    stack.pop()
            elif c == ']':
                if stack[-1] != '[':
                    print 'Error: unmatched ]'
                else:
                    stack.pop()
            elif c == '}':
                if stack[-1] != '{':
                    print 'Error: unmatched }'
                else:
                    stack.pop()

现在确实可以找到各种不匹配的括号。我们可以通过报告我们发现问题的行和列来稍微改进它。我们需要一个行号和列号计数器。

def error(c, line_number, column_number):
    print 'Error: unmatched', c, 'line', line_number, 'column', column_number

def check_parentheses(f):
    stack = list()
    line_number = 0
    for line in f:
        line_number = line_number + 1
        column_number = 0
        for c in line:
            column_number = column_number + 1
            if c == '(' or c == '[' or c == '{':
                stack.append(c)
            elif c == ')':
                if stack[-1] != '(':
                    error(')', line_number, column_number)
                else:
                    stack.pop()
            elif c == ']':
                if stack[-1] != '[':
                    error(']', line_number, column_number)
                else:
                    stack.pop()
            elif c == '}':
                if stack[-1] != '{':
                    error('}', line_number, column_number)
                else:
                    stack.pop()

还要注意我是如何添加一个辅助函数error来实际打印错误消息的。如果您想更改错误消息,您现在只需要在一个地方进行。

需要注意的另一件事是处理结束符号的情况都非常相似。我们也可以把它变成一个函数。

def check(stack, wanted, c, line_number, column_number):
    if stack[-1] != wanted:
        error(c, line_number, column_number)
    else:
        stack.pop()

def check_parentheses(f):
    stack = list()
    line_number = 0
    for line in f:
        line_number = line_number + 1
        column_number = 0
        for c in line:
            column_number = column_number + 1
            if c == '(' or c == '[' or c == '{':
                stack.append(c)
            elif c == ')':
                check(stack, '(', ')', line_number, column_number)
            elif c == ']':
                check(stack, '[', ']', line_number, column_number)
            elif c == '}':
                check(stack, '{', '}', line_number, column_number)

该程序可以进一步完善,但现在应该足够了。我将在最后包含整个代码。

请注意,该程序只关心各种括号。如果您真的想检查整个 Python 程序的语法正确性,则需要解析 Python 的所有语法,这非常复杂,对于一个 Stack Overflow 答案来说太多了。如果那是您真正想要的,请提出后续问题。

整个程序:

import sys

def error(c, line_number, column_number):
    print 'Error: unmatched', c, 'line', line_number, 'column', column_number

def check(stack, wanted, c, line_number, column_number):
    if stack[-1] != wanted:
        error(c, line_number, column_number)
    else:
        stack.pop()

def check_parentheses(f):
    stack = list()
    line_number = 0
    for line in f:
        line_number = line_number + 1
        column_number = 0
        for c in line:
            column_number = column_number + 1
            if c == '(' or c == '[' or c == '{':
                stack.append(c)
            elif c == ')':
                check(stack, '(', ')', line_number, column_number)
            elif c == ']':
                check(stack, '[', ']', line_number, column_number)
            elif c == '}':
                check(stack, '{', '}', line_number, column_number)

def main():
    filename = sys.argv[1]
    try:
        f = file(filename)
    except IOError:
        sys.stderr.write('Error: Cannot open file %s' % filename)
        sys.exit(1)
    check_parentheses(f)
    f.close()

main()
于 2009-12-10T07:48:05.680 回答
1

我想如果你改变:

            if line=='(':
                 c1=line.count('(')
            elif line==')':
                 c2=line.count(')')
            elif line=='[':
                 c3=line.count('[')
            elif line==']':
                 c4=line.count(']')
            elif line=='':
                break

类似于:

SearchFor = ['(', ')', '[', ']']
d = {}
for itm in SearchFor:
    d[itm] = line.count(itm)


# Then do the comparison
if d['['] == d[']'] and  d['('] == d[')']:
     print "Valid Syntax"
else:
     print "Invalid Syntax" #You could look at each to find the exact cause.

以及While True:其他人提到的。我错过了。:0)

于 2009-12-10T01:55:18.527 回答
1

删除 'while True' 行和这个位:

elif line=='':
    break

然后替换这个:

for line in filename:
    line=f.readline()

有了这个:

for line in f:

现在您将遍历文件中的行。

接下来,替换所有这些类型的东西:

if line=='(':
    c1=line.count('(')

和:

    c1+=line.count('(')

if 和 elif 行只是阻止您在应该计数时进行计数。如果该行没有您要查找的内容,则计数将为 0,这很好。

这至少应该让你更接近解决方案。

于 2009-12-10T01:55:31.880 回答
1

我相信,您正在寻找平衡的符号检查器。最好使用堆栈。

  1. 做一个空栈,

  2. 对于字符串中的每个符号:

    2.1 如果符号是开盘符号,则将其压入堆栈。

    2.2 如果它是一个结束符号,那么

    2.2.1 如果堆栈为空,则为假。

    2.2.2 如果栈顶与结束符号不匹配,返回false。[如果您正在检查匹配的大括号,请检查此步骤]

    2.2.3 弹出堆栈。

  3. 如果堆栈为空,则返回 true,否则返回 false。

hth。

于 2009-12-10T02:08:06.887 回答
0

我的解决方案将尝试帮助您更准确地理解执行此操作的方法,并希望您在此过程中对数据结构有所了解。

正确执行此操作,您将需要使用stack。您需要提取 (, ), [, 和 ] 的所有实例(可能使用正则表达式...提示)并遍历生成的数组:

假设你的文件是这样的:

(this [is] foobar)

您的正则表达式将产生这个数组:

['(', '[', ']', ')'] 

你会pop(0)从这个数组中取出一个堆栈。

算法

1) 将所有标签 {(,),[,]} 放入一个数组中。

2) 对于数组中的每个元素,从中弹出(0) 并将其推送到您的堆栈中。对它之前的元素进行测试。如果它关闭它之前的元素,则从数组中弹出两次(例如,如果堆栈上有'(',并且要压入堆栈的下一个元素是')',则')'关闭' (',所以你同时弹出它们。) 如果没有,请继续。

3)如果你的数组是空的并且当这结束时你的堆栈是空的,那么你的文件格式正确。如果不是,那么您的文件格式不正确{类似于 (foo[bar)] }。

奖励:正则表达式:REGEX = re.compile(r"\)\(\[\]"), REGEX.findall(您要搜索的字符串)。在此处查看有关 Python 正则表达式的更多信息。

于 2009-12-10T02:00:20.560 回答
0

你想确保它们的括号和大括号匹配吗?那个“[(])”失败了?如果没有,那么您就走在了正确的道路上,只是您需要将“=”更改为“+=”。您正在丢弃前几行的值。

于 2009-12-10T01:50:12.500 回答
0

所有这些答案都是错误的,并且在所有情况下都不起作用,所以要么使用 python 解析器,例如 tokenize 等,要么只使用它

计数 = min(text.count("("), text.count(")"))

于 2009-12-10T06:38:29.157 回答