クリスタル ボールも OP からの情報もないため、EPO の Web サイトを少し調べました。自由にダウンロードできる毎週の特許情報ファイルが見つかりました。ウェブサイトでは 2006 年に utf8/XML に置き換えられると書かれていますが、cp500/SGML で引き続き利用できます :-)。2009年第27週のファイルを入手。2 つのファイル s350927[ab].bin を含む zip です。「bin」は「非 XML」を意味します。スペック取れた!「独自コード」は実際にはBINARYフィールドである可能性があります。各レコードには、固定の 252 バイトのヘッダーがあります。最初の 5 バイトは EBCDIC のレコード長です。たとえば、16 進数の F0F2F2F0F8 -> 2208 バイトです。固定ヘッダーの最後の 2 バイトは、次の可変部分の BINARY 長 (冗長) です。中央には、いくつかのテキスト フィールド、2 つの 2 バイト バイナリ フィールド、および 1 つの 4 バイト バイナリ フィールドがあります。バイナリ フィールドはグループ内のシリアル番号ですが、私が見たのは 1 だけです。
例 (s350927b.bin の最後のレコード):
Record number: 7266
pprint of header text and binary slices:
['EPB102055619 TXT00000001',
1,
' 20090701200927 08013627.8 EP20090528NN ',
1,
1,
' T *lots of spaces snipped*']
Edited version of the rather long SGML:
<PATDOC FILE="08013627.8" CY=EP DNUM=2055619 KIND=B1 DATE=20090701 STATUS=N>
*snip*
<B541>DE<B542>Windschutzeinheit für ein Motorrad
<B541>EN<B542>Windshield unit for saddle-ride type vehicle
<B541>FR<B542>Unité pare-brise pour motocyclette</B540>
*snip*
</PATDOC>
ヘッダーまたはトレーラー レコードはなく、この 1 つのレコード形式だけです。
つまり、OP の年次ファイルがこのようなものであれば、彼を助けることができるかもしれません。
更新:上記は「私のタイムゾーンの午前2時」バージョンです。ここにもう少し情報があります:
OP は次のように述べています。「各ファイルの先頭には、ファイルの長さを示す ASCII の数字がいくつかあります。」...それを翻訳すると、「各レコードの先頭には、レコードの長さを正確に示すEBCDICの 5桁の数字があります」と、(非常にあいまいな) 一致があります。
ドキュメンテーション ページの URL は次のとおりです。 http://docs.epoline.org/ebd/info.htm
言及されている最初のファイルは仕様です。
週次データのダウンロードページの URL は次のとおりです: http://ebd2.epoline.org/jsp/ebdst35.jsp
考察:私が見たデータはST.35シリーズです。ダウンロード可能な ST.32 もありますが、これは SGML コンテンツのみを含む並列バージョンのようです ("reduced cp437/850"、1 行に 1 つのタグ)。これは、ST.35 レコードの固定長ヘッダーのフィールドがあまり重要ではない可能性があるため、スキップできることを示しています。これにより、トランスコーディング タスクが大幅に簡素化されます。
価値のあるものとして、これが私の(調査、真夜中以降に書かれた)コードです:
[更新2:コードを少し整理しました。機能の変更なし]
from pprint import pprint as pp
import sys
from struct import unpack
HDRSZ = 252
T = '>s' # text
H = '>H' # binary 2 bytes
I = '>I' # binary 4 bytes
hdr_defn = [
6, T,
38, H,
40, T,
94, I,
98, H,
100, T,
251, H, # length of following SGML text
HDRSZ + 1
]
# above positions as per spec, reduce to allow for counting from 1
for i in xrange(0, len(hdr_defn), 2):
hdr_defn[i] -= 1
def records(fname, output_encoding='latin1', debug=False):
xlator=''.join(chr(i).decode('cp500').encode(output_encoding, 'replace') for i in range(256))
# print repr(xlator)
def xlate(ebcdic):
return ebcdic.translate(xlator)
# return ebcdic.decode('cp500') # use this if unicode output desired
f = open(fname, 'rb')
recnum = -1
while True:
# get header
buff = f.read(HDRSZ)
if not buff:
return # EOF
recnum += 1
if debug: print "\nrecnum", recnum
assert len(buff) == HDRSZ
recsz = int(xlate(buff[:5]))
if debug: print "recsz", recsz
# split remainder of header into text and binary pieces
fields = []
for i in xrange(0, len(hdr_defn) - 2, 2):
ty = hdr_defn[i + 1]
piece = buff[hdr_defn[i]:hdr_defn[i+2]]
if ty == T:
fields.append(xlate(piece))
else:
fields.append(unpack(ty, piece)[0])
if debug: pp(fields)
sgmlsz = fields.pop()
if debug: print "sgmlsz: %d; expected: %d - %d = %d" % (sgmlsz, recsz, HDRSZ, recsz - HDRSZ)
assert sgmlsz == recsz - HDRSZ
# get sgml part
sgml = f.read(sgmlsz)
assert len(sgml) == sgmlsz
sgml = xlate(sgml)
if debug: print "sgml", sgml
yield recnum, fields, sgml
if __name__ == "__main__":
maxrecs = int(sys.argv[1]) # dumping out the last `maxrecs` records in the file
fname = sys.argv[2]
keep = [None] * maxrecs
for recnum, fields, sgml in records(fname):
# do something useful here
keep[recnum % maxrecs] = (recnum, fields, sgml)
keep.sort()
for k in keep:
if k:
recnum, fields, sgml = k
print
print recnum
pp(fields)
print sgml