1

次のルールに準拠している場合は、文字列を確認する必要があります:http ://www.w3.org/TR/widgets/#zip-rel-path

Zip-rel-path   = [locale-folder] *folder-name file-name /
                 [locale-folder] 1*folder-name
locale-folder  = %x6C %x6F %x63 %x61 %x6C %x65 %x73
                 "/" lang-tag "/"
folder-name    = file-name "/"
file-name      = 1*allowed-char
allowed-char   = safe-char / zip-UTF8-char
zip-UTF8-char  = UTF8-2 / UTF8-3 / UTF8-4
safe-char      = ALPHA  / DIGIT / SP  / "$" / "%" / 
                 "'"    / "-"   / "_" / "@" / "~" /
                 "("    / ")"   / "&" / "+" / "," /
                 "="    / "["   / "]" / "."
UTF8-2         = %xC2-DF UTF8-tail
UTF8-3         = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
                 %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
UTF8-4         = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
                 %xF4 %x80-8F 2( UTF8-tail )
UTF8-tail      = %x80-BF
lang-tag       = primary-subtag *( "-" subtag )
primary-subtag = 1*8low-alphasubtag         = 1*8(alphanum)
alphanum       = low-alpha  / DIGITlow-alpha      = %x61-7a

上記のルールに正確に基づいたコード例が役立ちます。私はABNFに精通していません。ABNFを解析する方法は必要ありません。必要なのは、ABNFに慣れているか理解している人が、正規表現を使用したPythonコードなどの方法で手動で変換した上記のルールだけです。実際には、文字列を入力し、最終的には文字列を入力し、ルールが一致するかどうかにかかわらずtrueまたはfalseを返す関数として、上記のルールに対して検証します。それで、質問の形でそれを置くために:これはPythonで実装されたときにどのように見えるでしょうか?

UTF8のドキュメントから、上記のルールの一部の多くは、文字列がutf8であるかどうかをチェックしていることがわかります: https ://www.rfc-editor.org/rfc/rfc3629

UTF8-char   = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
   UTF8-1      = %x00-7F
   UTF8-2      = %xC2-DF UTF8-tail
   UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
                 %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
   UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
                 %xF4 %x80-8F 2( UTF8-tail )
   UTF8-tail   = %x80-BF  
4

2 に答える 2

2

おそらくpyparsingを試してみてください。これは、目的に合わせて簡単に変更できるpyparsingWebサイトの簡単な例です。

于 2012-08-20T16:31:59.123 に答える
1

私はあなたのためにパーサーを書こうとしました。

バルクがUTF-8のテストであることに同意します。これは、文字列に値が既に含まれている場合は冗長です(UTF-8はファイルシステムのエンコーディングであり、Unicodeは有効なUTF-8の内部表現です)。それは確かに物事を非常に単純化します。

私が理解しているように、BNFは次のように述べています。

  • locale-folder(オプション)は、文字列'locale/'の後にlang-tagが続きます
  • lang-tagの形式は、「en」、「en-us」、「en-123」、「en-us-1」などです。
    • '-'文字で区切られた少なくとも1つのトークン
    • 各トークンは1〜8文字です
    • 最初のトークンには小文字のみを含めることができます
    • 次のトークンは小文字と数字の組み合わせです
  • オプションのロケールの後に、次のことができます。
    • 単一のファイル名または
    • パス( 「/」で区切られた一連のフォルダー名)または
    • パスの後にファイル名が続く
  • folder-namefile-nameは一種のユニコードです。各キャラクターはどちらかです
    • AZ、az、0-9、または
    • 「$%'-_ @〜()&+、=[]」のいずれか。
    • u007Fより上の任意の文字(UTF8の2、3、および4バイト文字)

とは言うものの、ここに簡単な実装があります(デバッグの目的で、解析からの出力をキャプチャします。これはデバッグのために行いましたが、不要な場合は削除してください)。パスにエラーがあると、ZipRelPathコンストラクターがValueErrorを発生させます。

import re

class ZipRelPath:
    FILE_NAME_RE = re.compile(u"^[a-zA-Z0-9 \$\%\'\-_@~\(\)&+,=\[\]\.\u0080-\uFFFF]+$")
    LANG_TAG_RE  = re.compile("^[a-z]{1,8}(\-[a-z0-9]{1,8})*$")
    LOCALES      = "locales/"

    def __init__(self, path):
        self.path = path
        self.lang_tag = None
        self.folders = []
        self.file_name = None

        self._parse_locales()
        self._parse_folders()

    def _parse_locales(self):
        """Consumes any leading 'locales' and lang-tag"""
        if self.path.startswith(ZipRelPath.LOCALES):
            self.path = self.path[len(ZipRelPath.LOCALES):]
            self._parse_lang_tag()

    def _parse_lang_tag(self):
        """Parses, consumes and validates the lang-tag"""
        self.lang_tag, _, self.path = self.path.partition("/")
        if not self.path:
            raise ValueError("lang-tag missing closing /")
        if not ZipRelPath.LANG_TAG_RE.match(self.lang_tag):
            raise ValueError(u"'%s' is not a valid language tag" % self.lang_tag)

    def _parse_folders(self):
        """Handles the folders and file-name after the locale"""
        while (self.path):
            self._parse_folder_or_file()

        if not self.folders and not self.file_name:
            raise ValueError("Missing folder or file name")

    def _parse_folder_or_file(self):
        """Each call consumes a single path entry, validating it"""
        folder_or_file, _, self.path = self.path.partition("/")
        if not ZipRelPath.FILE_NAME_RE.match(folder_or_file):
            raise ValueError(u"'%s' is not a valid file or folder name" % folder_or_file)
        if self.path:
            self.folders.append(folder_or_file)
        else:
            self.file_name = folder_or_file

    def __unicode__(self):
        return u"ZipRelPath [lang-tag: %s, folders: %s, file_name: %s" % (self.lang_tag, self.folders, self.file_name)

そして、テストの短いセット:

GOOD = [
    "$%'-_@~()&+,=[].txt9",
    "my/path/to/file.txt",
    "locales/en/file.txt",
    "locales/en-us/file.txt",
    "locales/en-us-abc123-xyz/file.txt",
    "locales/abcdefgh-12345678/file.txt",
    "locales/en/my/path/to/file.txt",
    u"my\u00A5\u0160\u039E\u04FE\u069E\u0BCC\uFFFD/path/to/file.txt"
]
BAD   = [
    "",
    "/starts/with/slash",
    "bad^file",
    "locales//bad/locale",
    "locales/en123/bad/locale",
    "locales/EN/bad/locale",
    "locales/en-US/bad/locale",
    ]

for path in GOOD:
    print unicode(ZipRelPath(path))

for path in BAD:
    try:
        zip = ZipRelPath(path)
        raise Exception("Illegal path {0} was accepted by {1}".format(path, zip))
    except ValueError as exception:
        print "Incorrect path '{0}' fails with: {1}".format(path, exception)

生成するもの:

ZipRelPath [lang-tag: None, folders: [], file_name: $%'-_@~()&+,=[].txt9
ZipRelPath [lang-tag: None, folders: ['my', 'path', 'to'], file_name: file.txt
ZipRelPath [lang-tag: en, folders: [], file_name: file.txt
ZipRelPath [lang-tag: en-us, folders: [], file_name: file.txt
ZipRelPath [lang-tag: en-us-abc123-xyz, folders: [], file_name: file.txt
ZipRelPath [lang-tag: abcdefgh-12345678, folders: [], file_name: file.txt
ZipRelPath [lang-tag: en, folders: ['my', 'path', 'to'], file_name: file.txt
ZipRelPath [lang-tag: None, folders: [u'my\xa5\u0160\u039e\u04fe\u069e\u0bcc\ufffd', u'path', u'to'], file_name: file.txt
Incorrect path '' fails with: Missing folder or file name
Incorrect path '/starts/with/slash' fails with: '' is not a valid file or folder name
Incorrect path 'bad^file' fails with: 'bad^file' is not a valid file or folder name
Incorrect path 'locales//bad/locale' fails with: '' is not a valid language tag
Incorrect path 'locales/en123/bad/locale' fails with: 'en123' is not a valid language tag
Incorrect path 'locales/EN/bad/locale' fails with: 'EN' is not a valid language tag
Incorrect path 'locales/en-US/bad/locale' fails with: 'en-US' is not a valid language tag

テストケースのいずれかが失敗した場合はお知らせください。修正できるかどうかを確認します。

于 2012-08-29T09:31:18.603 に答える