1

ファイルを開き、各行を検索して、その行に閉じられていない括弧と引用符があるかどうかを確認する簡単な方法を探しています。行に括弧/引用符が閉じられていない場合、その行をファイルに出力したいと思います。if/forステートメントの醜い塊でそれを行うことができることは知っていますが、Pythonはおそらくreモジュール(私は何も知らない)または他の何かを使用した方が良い方法があることを知っていますが、言語を十分に知りませんそうする。

ありがとう!

編集:いくつかの例の行。これをメモ帳などにコピーし、ワードラップをオフにすると読みやすくなる場合があります (一部の行はかなり長くなる可能性があります)。また、ファイルには 10 万行を超える行があるため、何か効率的なものがあれば素晴らしいでしょう!

SL  ID=0X14429A0B TY=STANDARD OWN=0X429A03 EXT=22 SLTK=0X1C429A0B MP=0X684003F0 SUB=0X24400007
RT  ID=0X18429A19 TY=CALONSC OWN=0X14429A0B EXLP=0X14429A0C CMDS=(N:0X8429A04,C:0X14429A0B) SGCC=2 REL=1 DESC="AURANT YD-INDSTRY LD" ATIS=T
RT  ID=0X18429A1A TY=CALONSC OWN=0X14429A0B EXLP=0X14429A08 CMDS=(R:0X8429A04,N:0X8429A05,C:0X14429A0B) SGCC=2 REL=2 DESC="AURANT YD TO TRK.1" ATIS=T
RT  ID=0X18429A1B TY=CALONSC OWN=0X14429A0B EXLP=0X14429A0A CMDS=(R:0X8429A04,R:0X8429A05,C:0X14429A0B) SGCC=2 REL=3 DESC="AURANT YD TO TRK.2" ATIS=T
SL  ID=0X14429A0C TY=STANDARD OWN=0X429A03 EXT=24 SLTK=0X1C429A0B MP=0X684003F1 SUB=0X24400007
RT  ID=0X18429A1C TY=CALONSC OWN=0X14429A0C EXLP=0X14429A0B CMDS=(N:0X8429A04,C:0X14429A0C) SGCC=2 REL=1 DESC="AURANT YD-INDSTRY LD" ATIS=T
TK  ID=0X1C429A08 TY=BLKTK OWN=0X429A03 EXT=12 LRMP=0X6C40BDAF LEN=5837 FSPD=60 PSPD=65 QUAL=TRK.1 MAXGE=0 MAXGW=0 JAL=4 ALT=12 SUB=0X24400007 RULES=(CTC:B:UP:0X24400007:485.7305:486.8359:T) LLON=-118.1766772 RLON=-118.1620059 LLAT=34.06838375 RLAT=34.07811764 LELE=416.6983 RELE=425.0596 ULAD=NO URAD=NO
PT  ID=0X20429A0F TY=STANDARD OWN=0X1C429A08 LTK=0X1C40006C RTK=0X1C429A0C REL=1 LEN=1 LQUAL="TRK.1" RQUAL="TRK.1"
PTK OWN=0X1C429A08 PID=0X1C429A13
4

8 に答える 8

6

逆方向に一致しない括弧 (つまり ")(") が存在しないと思われる場合は、次のようにすることができます。

with open("myFile.txt","r") as readfile, open("outFile.txt","w") as outfile:
    for line in readfile:
        if line.count("(") != line.count(")") or line.count('"') % 2 != 0:
            outfile.write(line)

それ以外の場合は、次のように、不一致を確認するために一度に 1 つずつカウントする必要があります。

with open("myFile.txt","r") as readfile, open("outFile.txt","w") as outfile:
    for line in readfile:
        count = 0
        for char in line:
            if char == ")":
                count -= 1
            elif char == "(":
                count += 1
            if count < 0:
                break
         if count != 0 or text.count('"') % 2 != 0:
             outfile.write(line)

それを処理するためのより良い方法は考えられません。Python は再帰的な正規表現をサポートしていないため、正規表現によるソリューションは適切です。

これについてもう 1 つ: データが与えられた場合、それを関数に入れて文字列を分割する方がよい場合があります。これは、次のように正規表現で簡単に実行できます。

import re
splitre = re.compile(".*?=(.*?)(?:(?=\s*?\S*?=)|(?=\s*$))")
with open("myFile.txt","r") as readfile, open("outFile.txt","w") as outfile:
    for line in readfile:
        def matchParens(text):
            count = 0
            for char in text:
                if char == ")":
                    count -= 1
                elif char == "(":
                    count += 1
                if count < 0:
                    break
            return count != 0 or text.count('"') % 2 != 0
        if any(matchParens(text) for text in splitre.findall(line)):
            outfile.write(line)

それがより良い理由は、各値のペアを個別にチェックするためです。そのため、ある値のペアに開き括弧があり、後の値のペアに閉じ括弧がある場合、不均衡な括弧がないとは見なされません。

于 2012-08-09T19:43:05.670 に答える
5

パーサー パッケージを使用するのはやり過ぎのように思えるかもしれませんが、非常に簡単です。

text = """\
SL  ID=0X14429A0B TY=STANDARD OWN=0X429A03 EXT=22 SLTK=0X1C429A0B MP=0X684003F0 SUB=0X24400007
RT  ID=0X18429A19 TY=CALONSC OWN=0X14429A0B EXLP=0X14429A0C CMDS=(N:0X8429A04,C:0X14429A0B) SGCC=2 REL=1 DESC="AURANT YD-INDSTRY LD" ATIS=T
RT  ID=0X18429A1A TY=CALONSC OWN=0X14429A0B EXLP=0X14429A08 CMDS=(R:0X8429A04,N:0X8429A05,C:0X14429A0B) SGCC=2 REL=2 DESC="AURANT YD TO TRK.1" ATIS=T
RT  ID=0X18429A1B TY=CALONSC OWN=0X14429A0B EXLP=0X14429A0A CMDS=(R:0X8429A04,R:0X8429A05,C:0X14429A0B) SGCC=2 REL=3 DESC="AURANT YD TO TRK.2" ATIS=T
SL  ID=0X14429A0C TY=STANDARD OWN=0X429A03 EXT=24 SLTK=0X1C429A0B MP=0X684003F1 SUB=0X24400007
RT  ID=0X18429A1C TY=CALONSC OWN=0X14429A0C EXLP=0X14429A0B CMDS=(N:0X8429A04,C:0X14429A0C) SGCC=2 REL=1 DESC="AURANT YD-INDSTRY LD" ATIS=T
TK  ID=0X1C429A08 TY=BLKTK OWN=0X429A03 EXT=12 LRMP=0X6C40BDAF LEN=5837 FSPD=60 PSPD=65 QUAL=TRK.1 MAXGE=0 MAXGW=0 JAL=4 ALT=12 SUB=0X24400007 RULES=(CTC:B:UP:0X24400007:485.7305:486.8359:T) LLON=-118.1766772 RLON=-118.1620059 LLAT=34.06838375 RLAT=34.07811764 LELE=416.6983 RELE=425.0596 ULAD=NO URAD=NO
PT  ID=0X20429A0F TY=STANDARD OWN=0X1C429A08 LTK=0X1C40006C RTK=0X1C429A0C REL=1 LEN=1 LQUAL="TRK.1" RQUAL="TRK.1"
PTK OWN=0X1C429A08 PID=0X1C429A13 GOOD
PTK OWN=0X1C429A(08 PID=0X1C429A13 BAD
PTK OWN=0X1C429A08 )PID=0X1C429A13 BAD
PTK OWN=0X1C(42(9A))08 PID=0X1C429A13 GOOD
PTK OWN=0X1C(42(9A))08 PID=0X1C42(9A13 BAD
PTK OWN=0X1C(42(9A))08 PID=0X1C42"("9A13 GOOD
"""

from pyparsing import nestedExpr, quotedString

paired_exprs = nestedExpr('(',')')  |  quotedString

for i, line in enumerate(text.splitlines(), start=1):
    # use pyparsing expression to strip out properly nested quotes/parentheses
    stripped_line = paired_exprs.suppress().transformString(line)

    # if there are any quotes or parentheses left, they were not 
    # properly nested
    if any(unwanted in stripped_line for unwanted in '()"\''):
        print i, ':', line

版画:

10 : PTK OWN=0X1C429A(08 PID=0X1C429A13 BAD
11 : PTK OWN=0X1C429A08 )PID=0X1C429A13 BAD
13 : PTK OWN=0X1C(42(9A))08 PID=0X1C42(9A13 BAD
于 2012-08-09T19:48:52.957 に答える
3
  1. 線からすべての興味深いシンボルを抽出するだけです。
  2. 開始記号をスタックにプッシュし、終了記号を取得するたびにスタックからポップします。
  3. スタックがきれいな場合、シンボルはバランスが取れています。スタックがアンダーフローするか、完全に巻き戻されない場合は、ラインのバランスが取れていません。

行をチェックするためのサンプル コードは次のとおりです。最初の行に迷い括弧を挿入しました。

d = """SL  ID=0X14429A0B TY=STANDARD OWN=0X429A(03 EXT=22 SLTK=0X1C429A0B MP=0X684003F0 SUB=0X24400007
RT  ID=0X18429A19 TY=CALONSC OWN=0X14429A0B EXLP=0X14429A0C CMDS=(N:0X8429A04,C:0X14429A0B) SGCC=2 REL=1 DESC="AURANT YD-INDSTRY LD" ATIS=T
RT  ID=0X18429A1A TY=CALONSC OWN=0X14429A0B EXLP=0X14429A08 CMDS=(R:0X8429A04,N:0X8429A05,C:0X14429A0B) SGCC=2 REL=2 DESC="AURANT YD TO TRK.1" ATIS=T
RT  ID=0X18429A1B TY=CALONSC OWN=0X14429A0B EXLP=0X14429A0A CMDS=(R:0X8429A04,R:0X8429A05,C:0X14429A0B) SGCC=2 REL=3 DESC="AURANT YD TO TRK.2" ATIS=T
SL  ID=0X14429A0C TY=STANDARD OWN=0X429A03 EXT=24 SLTK=0X1C429A0B MP=0X684003F1 SUB=0X24400007
RT  ID=0X18429A1C TY=CALONSC OWN=0X14429A0C EXLP=0X14429A0B CMDS=(N:0X8429A04,C:0X14429A0C) SGCC=2 REL=1 DESC="AURANT YD-INDSTRY LD" ATIS=T
TK  ID=0X1C429A08 TY=BLKTK OWN=0X429A03 EXT=12 LRMP=0X6C40BDAF LEN=5837 FSPD=60 PSPD=65 QUAL=TRK.1 MAXGE=0 MAXGW=0 JAL=4 ALT=12 SUB=0X24400007 RULES=(CTC:B:UP:0X24400007:485.7305:486.8359:T) LLON=-118.1766772 RLON=-118.1620059 LLAT=34.06838375 RLAT=34.07811764 LELE=416.6983 RELE=425.0596 ULAD=NO URAD=NO
PT  ID=0X20429A0F TY=STANDARD OWN=0X1C429A08 LTK=0X1C40006C RTK=0X1C429A0C REL=1 LEN=1 LQUAL="TRK.1" RQUAL="TRK.1"
PTK OWN=0X1C429A08 PID=0X1C429A13"""

def unbalanced(line):
    close_symbols = {'"' : '"', '(': ")", '[': ']', "'" : "'"}
    syms = [x for x in line if x in '\'"[]()']
    stack = []
    for s in syms:
        try:
            if len(stack) > 0 and s == close_symbols[stack[-1]]:
                stack.pop()
            else:
                stack.append(s)
        except: # catches stack underflow or closing symbol lookup
            return True
    return len(stack) != 0


print unbalanced("hello 'there' () []")
print unbalanced("hello 'there\"' () []")
print unbalanced("][")

lines = d.splitlines()  # in your case you can do open("file.txt").readlines()

print [line for line in lines if unbalanced(line)]

大きなファイルの場合、すべてのファイルをメモリに読み込みたくないので、代わりに次のようにフラグメントを使用します。

with open("file.txt") as infile:
    for line in infile:
        if unbalanced(line):
            print line
于 2012-08-09T19:42:53.157 に答える
1

正規表現 - 行にネストされた括弧が含まれていない場合、解決策は非常に簡単です。

for line in myFile:
    if re.search(r"\([^\(\)]*($|\()", line):
        #this line contains unbalanced parentheses.

ネストされたステートメントの可能性を扱っている場合は、もう少し複雑になります。

for line in myFile:
    paren_stack = []
    for char in line:
        if char == '(':
            paren_stack.append(char)
        elif char == ')':
            if paren_stack:
                paren_stack.pop()
            else:
                #this line contains unbalanced parentheses.
于 2012-08-09T19:45:07.993 に答える
0

私はちょうど次のようなことをします:

for line in open(file, r):
    if line.count('"') % 2 != 0 or line.count('(') != line.count(')'):
        print(line)

しかし、それがあなたのニーズにぴったり合うかどうかはわかりません。

より堅牢:

for line in open(file, r):
    paren_count = 0
    paren_count_start_quote = 0
    quote_open = False
    for char in line:
        if char == ')':
            paren_count -= 1
        elif char == '(':
            paren_count += 1
        elif char == '"':
            quote_open = not quote_open
            if quote_open:
                paren_count_start_quote = paren_count
            elif paren_count != paren_count_start_quote:
                print(line)
                break
        if paren_count < 0:
            break
    if quote_open or paren_count != 0:
        print(line)

堅牢なものはテストしていませんが、うまくいくはずです。次のようなことを確認するようになりました: ( " ) "、引用符内で閉じられた括弧のセットが行を印刷します。

于 2012-08-09T19:39:08.057 に答える
0

このコードを確認してください

from tokenize import *
def syntaxCheck(line):
    def readline():
        yield line
        yield ''
    par,quo,dquo = 0,0,0
    count = { '(': (1,0,0),')': (-1,0,0),"'": (0,1,0),'"':(0,0,1) }
    for countPar, countQuo,countDQuo in (
      count.get(token,(0,0))+(token,) for _,token,_,_,_ in tokenize(readline().__next__)):
        par  += countPar
        quo  ^= countQuo
        dquo ^= countDQuo
    return par,quo,dquo

単一の文字列トークンとしてカウントされるため、閉じた引用符内の括弧はカウントされないことに注意してください。

于 2012-08-09T19:50:36.140 に答える
-1

私の解決策はそれほど派手ではないかもしれませんが、括弧と引用符の数を数えるだけです。偶数にならない場合は、何かが足りないことがわかります。

于 2012-08-09T20:18:28.973 に答える
-1

括弧と引用符は各行で閉じる必要がありますか? その場合は、括弧と引用符で簡単なカウントを行うことができます。偶数の場合、それらは一致しています。奇数の場合、1 つが欠落しています。そのロジックを関数に入れ、テキスト ファイルの行を配列にダンプし、map を呼び出して配列内の各文字列に対して関数を実行します。

私のpythonはさびていますが、すべてが同じ行に「あるはず」であると仮定して、それを行う方法です。

于 2012-08-09T19:29:54.847 に答える