Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1''' 

2Conversion of text from a Crystallographic Information File (CIF) format to 

3unicode. CIF text is neither unicode nor bibtex/latex code. 

4 

5Rules for character formatting in CIF files are specified at: 

6https://www.iucr.org/resources/cif/spec/version1.1/semantics 

7''' 

8 

9import re 

10import html 

11 

12 

13subs_dict = { 

14 '\r': '', # Windows line ending 

15 '\t': ' ', # tabs 

16 

17 r'\a': u'\u03b1', # alpha 

18 r'\b': u'\u03b2', # beta 

19 r'\g': u'\u03b3', # gamma 

20 r'\d': u'\u03b4', # delta 

21 r'\e': u'\u03b5', # epsilon 

22 r'\z': u'\u03b6', # zeta 

23 r'\h': u'\u03b7', # eta 

24 r'\q': u'\u03b8', # theta 

25 r'\i': u'\u03b9', # iota 

26 r'\k': u'\u03ba', # kappa 

27 r'\l': u'\u03bb', # lambda 

28 r'\m': u'\u03bc', # mu 

29 r'\n': u'\u03bd', # nu 

30 r'\x': u'\u03be', # xi 

31 r'\o': u'\u03bf', # omicron 

32 r'\p': u'\u03c0', # pi 

33 r'\r': u'\u03c1', # rho 

34 r'\s': u'\u03c3', # sigma 

35 r'\t': u'\u03c4', # tau 

36 r'\u': u'\u03c5', # upsilon 

37 r'\f': u'\u03c6', # phi 

38 r'\c': u'\u03c7', # chi 

39 r'\y': u'\u03c8', # psi 

40 r'\w': u'\u03c9', # omega 

41 r'\A': u'\u0391', # Alpha 

42 r'\B': u'\u0392', # Beta 

43 r'\G': u'\u0393', # Gamma 

44 r'\D': u'\u0394', # Delta 

45 r'\E': u'\u0395', # Epsilon 

46 r'\Z': u'\u0396', # Zeta 

47 r'\H': u'\u0397', # Eta 

48 r'\Q': u'\u0398', # Theta 

49 r'\I': u'\u0399', # Ioto 

50 r'\K': u'\u039a', # Kappa 

51 r'\L': u'\u039b', # Lambda 

52 r'\M': u'\u039c', # Mu 

53 r'\N': u'\u039d', # Nu 

54 r'\X': u'\u039e', # Xi 

55 r'\O': u'\u039f', # Omicron 

56 r'\P': u'\u03a0', # Pi 

57 r'\R': u'\u03a1', # Rho 

58 r'\S': u'\u03a3', # Sigma 

59 r'\T': u'\u03a4', # Tau 

60 r'\U': u'\u03a5', # Upsilon 

61 r'\F': u'\u03a6', # Phi 

62 r'\C': u'\u03a7', # Chi 

63 r'\Y': u'\u03a8', # Psi 

64 r'\W': u'\u03a9', # Omega 

65 

66 r'\%a': u'\u00e5', # a-ring 

67 r'\/o': u'\u00f8', # o-slash 

68 r'\?i': u'\u0131', # dotless i 

69 r'\/l': u'\u0142', # Polish l 

70 r'\&s': u'\u00df', # German eszett 

71 r'\/d': u'\u0111', # barred d 

72 

73 r'\%A': u'\u00c5', # A-ring 

74 r'\/O': u'\u00d8', # O-slash 

75 r'\?I': 'I', # dotless I 

76 r'\/L': u'\u0141', # Polish L 

77 r'\&S': u'\u1e9e', # German Eszett 

78 r'\/D': u'\u0110', # barred D 

79 

80 r'\%': u'\u00b0', # degree 

81 r'--': u'\u2013', # dash 

82 r'---': u'\u2014', # single bond 

83 r'\\db': u'\u003d', # double bond 

84 r'\\tb': u'\u2261', # triple bond 

85 r'\\ddb': u'\u2248', # delocalized double bond 

86 r'\\sim': '~', 

87 r'\\simeq': u'\u2243', 

88 r'\\infty': u'\u221e', # infinity 

89 

90 r'\\times': u'\u00d7', 

91 r'+-': u'\u00b1', # plusminus 

92 r'-+': u'\u2213', # minusplus 

93 r'\\square': u'\u25a0', 

94 r'\\neq': u'\u2660', 

95 r'\\rangle': u'\u3009', 

96 r'\\langle': u'\u3008', 

97 r'\\rightarrow': u'\u2192', 

98 r'\\leftarrow': u'\u2190', 

99 

100 r"\'A": u'\u00c1', # A acute 

101 r"\'E": u'\u00c9', # E acute 

102 r"\'I": u'\u00cd', # I acute 

103 r"\'O": u'\u00d3', # O acute 

104 r"\'U": u'\u00da', # U acute 

105 r"\'Y": u'\u00dd', # Y acute 

106 r"\'a": u'\u00e1', # a acute 

107 r"\'e": u'\u00e9', # e acute 

108 r"\'i": u'\u00ed', # i acute 

109 r"\'o": u'\u00f3', # o acute 

110 r"\'u": u'\u00fa', # u acute 

111 r"\'y": u'\u00fd', # y acute 

112 r"\'C": u'\u0106', # C acute 

113 r"\'c": u'\u0107', # c acute 

114 r"\'L": u'\u0139', # L acute 

115 r"\'l": u'\u013a', # l acute 

116 r"\'N": u'\u0143', # N acute 

117 r"\'n": u'\u0144', # n acute 

118 r"\'R": u'\u0154', # R acute 

119 r"\'r": u'\u0155', # r acute 

120 r"\'S": u'\u015a', # S acute 

121 r"\'s": u'\u015b', # s acute 

122 r"\'Z": u'\u0179', # Z acute 

123 r"\'z": u'\u017a', # z acute 

124 r"\'G": u'\u01f4', # G acute 

125 r"\'g": u'\u01f5', # g acute 

126 r"\'K": u'\u1e30', # K acute 

127 r"\'k": u'\u1e31', # k acute 

128 r"\'M": u'\u1e3e', # M acute 

129 r"\'m": u'\u1e3f', # m acute 

130 r"\'P": u'\u1e54', # P acute 

131 r"\'p": u'\u1e55', # p acute 

132 r"\'W": u'\u1e82', # W acute 

133 r"\'w": u'\u1e83', # w acute 

134 r'\;A': u'\u0104', # A ogonek 

135 r'\;a': u'\u0105', # a ogonek 

136 r'\;E': u'\u0118', # E ogonek 

137 r'\;e': u'\u0119', # e ogonek 

138 r'\;I': u'\u012e', # I ogonek 

139 r'\;i': u'\u012f', # i ogonek 

140 r'\;U': u'\u0172', # U ogonek 

141 r'\;u': u'\u0173', # u ogonek 

142 r'\;O': u'\u01ea', # O ogonek 

143 r'\;o': u'\u01eb', # o ogonek 

144 r'\.C': u'\u010a', # C dot above 

145 r'\.c': u'\u010b', # c dot above 

146 r'\.E': u'\u0116', # E dot above 

147 r'\.e': u'\u0117', # e dot above 

148 r'\.G': u'\u0120', # G dot above 

149 r'\.g': u'\u0121', # g dot above 

150 r'\.I': u'\u0130', # I dot above 

151 r'\.Z': u'\u017b', # Z dot above 

152 r'\.z': u'\u017c', # z dot above 

153 r'\.A': u'\u0226', # A dot above 

154 r'\.a': u'\u0227', # a dot above 

155 r'\.O': u'\u022e', # O dot above 

156 r'\.o': u'\u022f', # o dot above 

157 r'\.B': u'\u1e02', # B dot above 

158 r'\.b': u'\u1e03', # b dot above 

159 r'\.D': u'\u1e0a', # D dot above 

160 r'\.d': u'\u1e0b', # d dot above 

161 r'\.F': u'\u1e1e', # F dot above 

162 r'\.f': u'\u1e1f', # f dot above 

163 r'\.H': u'\u1e22', # H dot above 

164 r'\.h': u'\u1e23', # h dot above 

165 r'\.M': u'\u1e40', # M dot above 

166 r'\.m': u'\u1e41', # m dot above 

167 r'\.N': u'\u1e44', # N dot above 

168 r'\.n': u'\u1e45', # n dot above 

169 r'\.P': u'\u1e56', # P dot above 

170 r'\.p': u'\u1e57', # p dot above 

171 r'\.R': u'\u1e58', # R dot above 

172 r'\.r': u'\u1e59', # r dot above 

173 r'\.S': u'\u1e60', # S dot above 

174 r'\.s': u'\u1e61', # s dot above 

175 r'\.T': u'\u1e6a', # T dot above 

176 r'\.t': u'\u1e6b', # t dot above 

177 r'\.W': u'\u1e86', # W dot above 

178 r'\.w': u'\u1e87', # w dot above 

179 r'\.X': u'\u1e8a', # X dot above 

180 r'\.x': u'\u1e8b', # x dot above 

181 r'\.Y': u'\u1e8e', # Y dot above 

182 r'\.y': u'\u1e8f', # y dot above 

183 r'\(A': u'\u0102', # A breve 

184 r'\(a': u'\u0103', # a breve 

185 r'\(E': u'\u0114', # E breve 

186 r'\(e': u'\u0115', # e breve 

187 r'\(G': u'\u011e', # G breve 

188 r'\(g': u'\u011f', # g breve 

189 r'\(I': u'\u012c', # I breve 

190 r'\(i': u'\u012d', # i breve 

191 r'\(O': u'\u014e', # O breve 

192 r'\(o': u'\u014f', # o breve 

193 r'\(U': u'\u016c', # U breve 

194 r'\(u': u'\u016d', # u breve 

195 r'\=A': u'\u0100', # A macron 

196 r'\=a': u'\u0101', # a macron 

197 r'\=E': u'\u0112', # E macron 

198 r'\=e': u'\u0113', # e macron 

199 r'\=I': u'\u012a', # I macron 

200 r'\=i': u'\u012b', # i macron 

201 r'\=O': u'\u014c', # O macron 

202 r'\=o': u'\u014d', # o macron 

203 r'\=U': u'\u016a', # U macron 

204 r'\=u': u'\u016b', # u macron 

205 r'\=Y': u'\u0232', # Y macron 

206 r'\=y': u'\u0233', # y macron 

207 r'\=G': u'\u1e20', # G macron 

208 r'\=g': u'\u1e21', # g macron 

209 r'\^A': u'\u00c2', # A circumflex 

210 r'\^E': u'\u00ca', # E circumflex 

211 r'\^I': u'\u00ce', # I circumflex 

212 r'\^O': u'\u00d4', # O circumflex 

213 r'\^U': u'\u00db', # U circumflex 

214 r'\^a': u'\u00e2', # a circumflex 

215 r'\^e': u'\u00ea', # e circumflex 

216 r'\^i': u'\u00ee', # i circumflex 

217 r'\^o': u'\u00f4', # o circumflex 

218 r'\^u': u'\u00fb', # u circumflex 

219 r'\^C': u'\u0108', # C circumflex 

220 r'\^c': u'\u0109', # c circumflex 

221 r'\^G': u'\u011c', # G circumflex 

222 r'\^g': u'\u011d', # g circumflex 

223 r'\^H': u'\u0124', # H circumflex 

224 r'\^h': u'\u0125', # h circumflex 

225 r'\^J': u'\u0134', # J circumflex 

226 r'\^j': u'\u0135', # j circumflex 

227 r'\^S': u'\u015c', # S circumflex 

228 r'\^s': u'\u015d', # s circumflex 

229 r'\^W': u'\u0174', # W circumflex 

230 r'\^w': u'\u0175', # w circumflex 

231 r'\^Y': u'\u0176', # Y circumflex 

232 r'\^y': u'\u0177', # y circumflex 

233 r'\^Z': u'\u1e90', # Z circumflex 

234 r'\^z': u'\u1e91', # z circumflex 

235 r'\"A': u'\u00c4', # A diaeresis 

236 r'\"E': u'\u00cb', # E diaeresis 

237 r'\"I': u'\u00cf', # I diaeresis 

238 r'\"O': u'\u00d6', # O diaeresis 

239 r'\"U': u'\u00dc', # U diaeresis 

240 r'\"a': u'\u00e4', # a diaeresis 

241 r'\"e': u'\u00eb', # e diaeresis 

242 r'\"i': u'\u00ef', # i diaeresis 

243 r'\"o': u'\u00f6', # o diaeresis 

244 r'\"u': u'\u00fc', # u diaeresis 

245 r'\"y': u'\u00ff', # y diaeresis 

246 r'\"Y': u'\u0178', # Y diaeresis 

247 r'\"H': u'\u1e26', # H diaeresis 

248 r'\"h': u'\u1e27', # h diaeresis 

249 r'\"W': u'\u1e84', # W diaeresis 

250 r'\"w': u'\u1e85', # w diaeresis 

251 r'\"X': u'\u1e8c', # X diaeresis 

252 r'\"x': u'\u1e8d', # x diaeresis 

253 r'\"t': u'\u1e97', # t diaeresis 

254 r'\~A': u'\u00c3', # A tilde 

255 r'\~N': u'\u00d1', # N tilde 

256 r'\~O': u'\u00d5', # O tilde 

257 r'\~a': u'\u00e3', # a tilde 

258 r'\~n': u'\u00f1', # n tilde 

259 r'\~o': u'\u00f5', # o tilde 

260 r'\~I': u'\u0128', # I tilde 

261 r'\~i': u'\u0129', # i tilde 

262 r'\~U': u'\u0168', # U tilde 

263 r'\~u': u'\u0169', # u tilde 

264 r'\~V': u'\u1e7c', # V tilde 

265 r'\~v': u'\u1e7d', # v tilde 

266 r'\~E': u'\u1ebc', # E tilde 

267 r'\~e': u'\u1ebd', # e tilde 

268 r'\~Y': u'\u1ef8', # Y tilde 

269 r'\~y': u'\u1ef9', # y tilde 

270 r'\<C': u'\u010c', # C caron 

271 r'\<c': u'\u010d', # c caron 

272 r'\<D': u'\u010e', # D caron 

273 r'\<d': u'\u010f', # d caron 

274 r'\<E': u'\u011a', # E caron 

275 r'\<e': u'\u011b', # e caron 

276 r'\<L': u'\u013d', # L caron 

277 r'\<l': u'\u013e', # l caron 

278 r'\<N': u'\u0147', # N caron 

279 r'\<n': u'\u0148', # n caron 

280 r'\<R': u'\u0158', # R caron 

281 r'\<r': u'\u0159', # r caron 

282 r'\<S': u'\u0160', # S caron 

283 r'\<s': u'\u0161', # s caron 

284 r'\<T': u'\u0164', # T caron 

285 r'\<t': u'\u0165', # t caron 

286 r'\<Z': u'\u017d', # Z caron 

287 r'\<z': u'\u017e', # z caron 

288 r'\<A': u'\u01cd', # A caron 

289 r'\<a': u'\u01ce', # a caron 

290 r'\<I': u'\u01cf', # I caron 

291 r'\<i': u'\u01d0', # i caron 

292 r'\<O': u'\u01d1', # O caron 

293 r'\<o': u'\u01d2', # o caron 

294 r'\<U': u'\u01d3', # U caron 

295 r'\<u': u'\u01d4', # u caron 

296 r'\<G': u'\u01e6', # G caron 

297 r'\<g': u'\u01e7', # g caron 

298 r'\<K': u'\u01e8', # K caron 

299 r'\<k': u'\u01e9', # k caron 

300 r'\<j': u'\u01f0', # j caron 

301 r'\<H': u'\u021e', # H caron 

302 r'\<h': u'\u021f', # h caron 

303 r'\>O': u'\u0150', # O double acute 

304 r'\>o': u'\u0151', # o double acute 

305 r'\>U': u'\u0170', # U double acute 

306 r'\>u': u'\u0171', # u double acute 

307 r'\,C': u'\u00c7', # C cedilla 

308 r'\,c': u'\u00e7', # c cedilla 

309 r'\,G': u'\u0122', # G cedilla 

310 r'\,g': u'\u0123', # g cedilla 

311 r'\,K': u'\u0136', # K cedilla 

312 r'\,k': u'\u0137', # k cedilla 

313 r'\,L': u'\u013b', # L cedilla 

314 r'\,l': u'\u013c', # l cedilla 

315 r'\,N': u'\u0145', # N cedilla 

316 r'\,n': u'\u0146', # n cedilla 

317 r'\,R': u'\u0156', # R cedilla 

318 r'\,r': u'\u0157', # r cedilla 

319 r'\,S': u'\u015e', # S cedilla 

320 r'\,s': u'\u015f', # s cedilla 

321 r'\,T': u'\u0162', # T cedilla 

322 r'\,t': u'\u0163', # t cedilla 

323 r'\,E': u'\u0228', # E cedilla 

324 r'\,e': u'\u0229', # e cedilla 

325 r'\,D': u'\u1e10', # D cedilla 

326 r'\,d': u'\u1e11', # d cedilla 

327 r'\,H': u'\u1e28', # H cedilla 

328 r'\,h': u'\u1e29', # h cedilla 

329 r'\`A': u'\u00c0', # A grave 

330 r'\`E': u'\u00c8', # E grave 

331 r'\`I': u'\u00cc', # I grave 

332 r'\`O': u'\u00d2', # O grave 

333 r'\`U': u'\u00d9', # U grave 

334 r'\`a': u'\u00e0', # a grave 

335 r'\`e': u'\u00e8', # e grave 

336 r'\`i': u'\u00ec', # i grave 

337 r'\`o': u'\u00f2', # o grave 

338 r'\`u': u'\u00f9', # u grave 

339 r'\`N': u'\u01f8', # N grave 

340 r'\`n': u'\u01f9', # n grave 

341 r'\`W': u'\u1e80', # W grave 

342 r'\`w': u'\u1e81', # w grave 

343 r'\`Y': u'\u1ef2', # Y grave 

344 r'\`y': u'\u1ef3', # y grave 

345} 

346 

347superscript_dict = { 

348 '0': u'\u2070', # superscript 0 

349 '1': u'\u00b9', # superscript 1 

350 '2': u'\u00b2', # superscript 2 

351 '3': u'\u00b3', # superscript 3 

352 '4': u'\u2074', # superscript 4 

353 '5': u'\u2075', # superscript 5 

354 '6': u'\u2076', # superscript 6 

355 '7': u'\u2077', # superscript 7 

356 '8': u'\u2078', # superscript 8 

357 '9': u'\u2079', # superscript 9 

358} 

359 

360subscript_dict = { 

361 '0': u'\u2080', # subscript 0 

362 '1': u'\u2081', # subscript 1 

363 '2': u'\u2082', # subscript 2 

364 '3': u'\u2083', # subscript 3 

365 '4': u'\u2084', # subscript 4 

366 '5': u'\u2085', # subscript 5 

367 '6': u'\u2086', # subscript 6 

368 '7': u'\u2087', # subscript 7 

369 '8': u'\u2088', # subscript 8 

370 '9': u'\u2089', # subscript 9 

371} 

372 

373 

374def replace_subscript(s: str, subscript=True) -> str: 

375 

376 target = '~' 

377 rdict = subscript_dict 

378 if not subscript: 

379 target = '^' 

380 rdict = superscript_dict 

381 

382 replaced = [] 

383 inside = False 

384 for char in s: 

385 if char == target: 

386 inside = not inside 

387 elif not inside: 

388 replaced += [char] 

389 # note: do not use char.isdigit - this also matches (sub/super)scripts 

390 elif char in rdict: 

391 replaced += [rdict[char]] 

392 else: 

393 replaced += [char] 

394 

395 return ''.join(replaced) 

396 

397 

398def multiple_replace(text: str, adict) -> str: 

399 rx = re.compile('|'.join(map(re.escape, adict))) 

400 

401 def one_xlat(match): 

402 return adict[match.group(0)] 

403 

404 return rx.sub(one_xlat, text) 

405 

406 

407def format_unicode(s: str) -> str: 

408 """Converts a string in CIF text-format to unicode. Any HTML tags 

409 contained in the string are removed. HTML numeric character references 

410 are unescaped (i.e. converted to unicode). 

411 

412 Parameters: 

413 

414 s: string 

415 The CIF text string to convert 

416 

417 Returns: 

418 

419 u: string 

420 A unicode formatted string. 

421 """ 

422 

423 s = html.unescape(s) 

424 s = multiple_replace(s, subs_dict) 

425 tagclean = re.compile('<.*?>') 

426 return re.sub(tagclean, '', s) 

427 

428 

429def handle_subscripts(s: str) -> str: 

430 s = replace_subscript(s, subscript=True) 

431 s = replace_subscript(s, subscript=False) 

432 return s