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
[何らかの出力]

毎回ファイル名を入力する必要があります。プログラムを複数回実行するためにコマンドを入力する必要はありません。初回以降は、矢印キーを使用してシェルのコマンド履歴から取得できます。コマンド ラインからファイル名を取得する場合は、代わりに次のようにします。

$ python foo.py testfile
[一部の出力]
$ python foo.py testfile
[一部の出力]
$ python foo.py testfile
[一部の出力]

これにより、2 回目のテスト時に、上矢印キーと Enter キー以外を入力する必要がなくなります。これはささやかな便利さですが、重要なことです。ソフトウェアを開発しているときは、小さなことでさえ煩わしくなることがあります。それは、長い散歩をしているときに足の下に大きな砂粒のようなものがあります.

Python でコマンド ライン引数にアクセスするには、リストが必要です sys.argv。プログラムに関連する変更:

import sys
filename = sys.argv[1]

プロンプトを表示したい場合は、組み込みinput関数以外のものを使用する必要があります。ユーザーが入力したものは何でも Python 式として解釈し、あらゆる種類の問題を引き起こします。を使用して読み取ることができますsys.stdin.readline

とにかく、filename変数に安全に格納されたファイルの名前を取得しました。それを何とかする時が来ました。あなたのparentheses関数はほとんどすべてのことを行いますが、経験上、それが最善の方法ではないことがよくあります。代わりに、すべての関数は 1 つのことだけを実行する必要がありますが、それをうまく実行する必要があります。

ファイルを実際に開いたり閉じたりする部分は、実際のカウントとは別にしておくことをお勧めします。これにより、残りのことを心配する必要がないため、カウントのロジックが簡素化されます。コード内:

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()

再配置に加えて、他にもいくつか変更を加えました。まず、エラー メッセージを標準エラー出力に書き込みます。これは適切な方法であり、シェル ユーザーが出力をリダイレクトすることに驚かされることが少なくなることを意味します。(それがあなたにとって意味をなさない場合でも、心配する必要はありません。今のところ、それを当然のこととして受け入れてください。)

次に、エラーが発生した場合は、プログラムを終了しsys.exit(1)ます。これは、プログラムを開始した人に、プログラムが失敗したことを示します。Unix シェルでは、これにより次のようなことができます。

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

もちろん、シェル スクリプトは、単に成功または失敗を報告するだけでなく、もっと興味深いことを行う可能性があります。たとえば、壊れたファイルをすべて削除したり、ファイルを書いた人に電子メールで修正を依頼したりします。美点は、チェッカー プログラムを作成するあなたが気にする必要がないことです。プログラムの終了コードを適切に設定するだけで、あとはシェル スクリプトの作成者に任せることができます。

次のステップは、実際にファイルの内容を読み取ることです。これは、さまざまな方法で行うことができます。最も簡単な方法は、次のように行ごとに行うことです。

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また、エラー メッセージを実際に出力するためのヘルパー関数 を追加した方法にも注意してください。エラー メッセージを変更する場合は、1 か所で行うだけで済みます。

もう 1 つの注目すべき点は、終了記号を処理するケースがすべて非常に似ていることです。それを関数にすることもできます。

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 の構文をすべて解析する必要があります。これはかなり複雑で、1 つのスタック オーバーフローの回答には多すぎます。それが本当に必要な場合は、フォローアップの質問をしてください。

プログラム全体:

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

私はあなたがバランスの取れたシンボルチェッカーを探していると信じています。スタックを使用することをお勧めします。

  1. 空のスタックを作成し、

  2. 文字列内の各記号について:

    2.1シンボルが開始シンボルである場合、それをスタックにプッシュします。

    2.2終了記号の場合、

    2.2.1スタックが空の場合、それはfalseです。

    2.2.2スタックの最上位が終了記号と一致しない場合は、falseを返します。[中括弧が一致するかどうかを確認する場合は、この手順を確認してください]

    2.2.3スタックをポップします。

  3. スタックが空の場合はtrueを返し、そうでない場合はfalseを返します。

hth。

于 2009-12-10T02:08:06.887 に答える
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 に答える
0

私のソリューションは、これを行うためのもう少し正確な方法を理解するのに役立ちます。うまくいけば、その過程でデータ構造について少し学ぶことができます.

これを適切に行うには、 stackを使用する必要があります。(、)、[、および] (おそらく正規表現を使用して... ヒント) のすべてのインスタンスを取り出し、生成される配列を調べます。

ファイルが次のようになっているとします。

(this [is] foobar)

正規表現により、次の配列が生成されます。

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

pop(0)この配列からスタックに入れます。

アルゴリズム的に:

1) すべてのタグ {(,),[,]} を配列に入れます。

2) 配列内の各要素について、そこから pop(0) し、スタックにプッシュします。その前の要素に対してテストします。その前の要素を閉じる場合、pop() は配列から 2 回実行します (たとえば、スタックに '(' があり、スタックにプッシュされる次の要素が ')' の場合、')' は ' を閉じます。 ('、両方をポップします。) そうでない場合は、続行します。

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 パーサーを使用するか、単にこれを使用してください。

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

于 2009-12-10T06:38:29.157 に答える