web-dev-qa-db-ja.com

Python:エスケープ時にjson.loadsチョーク

JSONオブジェクト(プロトタイプでフォーマットされた)をASPサーバーに送信しているアプリケーションがあります。サーバー上で、Python 2.6 "json"モジュールが試行しますJSONをloads()しますが、バックスラッシュの組み合わせで窒息します。

>>> s
'{"FileExists": true, "Version": "4.3.2.1", "Path": "\\\\Host\\dir\\file.exe"}'

>>> tmp = json.loads(s)
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
  {... blah blah blah...}
  File "C:\Python26\lib\json\decoder.py", line 155, in JSONString
    return scanstring(match.string, match.end(), encoding, strict)
  ValueError: Invalid \escape: line 1 column 58 (char 58)

>>> s[55:60]
u'ost\\d'

したがって、列58はエスケープされた円記号です。これはきちんと逃げたと思いました! UNCは\\Host\dir\file.exeなので、スラッシュを2倍にしました。しかし、どうやらこれは良くありません。誰かが助けることができますか?最後の手段として、\を/に変換してから再び戻すことを検討していますが、これは私にとっては本当のハックのようです。

前もって感謝します!

18
Chris

正しいjsonは次のとおりです。

_r'{"FileExists": true, "Version": "4.3.2.1", "Path": "\\\\Host\\dir\\file.exe"}'
_

文字rを省略した場合は、Python)の場合も_\_をエスケープする必要があることに注意してください。

_>>> import json
>>> d = json.loads(s)
>>> d.keys()
[u'FileExists', u'Path', u'Version']
>>> d.values()
[True, u'\\\\Host\\dir\\file.exe', u'4.3.2.1']
_

違いに注意してください:

_>>> repr(d[u'Path'])
"u'\\\\\\\\Host\\\\dir\\\\file.exe'"
>>> str(d[u'Path'])
'\\\\Host\\dir\\file.exe'
>>> print d[u'Path']
\\Host\dir\file.exe
_

Python REPLデフォルトでオブジェクトのrepr(obj)を出力しますobj

_>>> class A:
...   __str__ = lambda self: "str"
...   __repr__  = lambda self: "repr"
... 
>>> A()
repr
>>> print A()
str
_

したがって、元のs文字列はJSON用に適切にエスケープされません。エスケープされていない_'\d'_と_'\f'_が含まれています。 _print s_は_'\\d'_を表示する必要があります。そうでない場合、正しいJSONではありません。

注:JSON文字列は、バックスラッシュエスケープ( json.org )を使用して、二重引用符で囲まれた0個以上のUnicode文字のコレクションです。上記の例では、エンコーディングの問題(つまり、バイト文字列からユニコードへの変換、およびその逆の変換)をスキップしました。

23
jfs

例外は問題のあるエスケープ文字のインデックスを提供するので、私が開発したこの小さなハックは素晴らしいかもしれません:)

def fix_JSON(json_message=None):
    result = None
    try:        
        result = json.loads(json_message)
    except Exception as e:      
        # Find the offending character index:
        idx_to_replace = int(e.message.split(' ')[-1].replace(')',''))      
        # Remove the offending character:
        json_message = list(json_message)
        json_message[idx_to_replace] = ' '
        new_message = ''.join(json_message)     
        return fix_JSON(json_message=new_message)
    return result
8
Blairg23
>>> s
'{"FileExists": true, "Version": "4.3.2.1", "Path": "\\\\Host\\dir\\file.exe"}'
>>> print s
{"FileExists": true, "Version": "4.3.2.1", "Path": "\\Host\dir\file.exe"}

文字列を実際にエスケープしていないため、\d\fなどの無効なエスケープコードを解析しようとしています。 json2.js などの十分にテストされたJSONエンコーダーの使用を検討してください。

1
John Millikin