|
4 | 4 | import os |
5 | 5 | import pathlib |
6 | 6 | import shutil |
| 7 | +import string |
7 | 8 | import subprocess |
8 | 9 | import sys |
9 | 10 | import time |
@@ -196,6 +197,119 @@ def data_kind(data=None, x=None, y=None, z=None, required_z=False, required_data |
196 | 197 | return kind |
197 | 198 |
|
198 | 199 |
|
| 200 | +def non_ascii_to_octal(argstr): |
| 201 | + r""" |
| 202 | + Translate non-ASCII characters to their corresponding octal codes. |
| 203 | +
|
| 204 | + Currently, only characters in the ISOLatin1+ charset and |
| 205 | + Symbol/ZapfDingbats fonts are supported. |
| 206 | +
|
| 207 | + Parameters |
| 208 | + ---------- |
| 209 | + argstr : str |
| 210 | + The string to be translated. |
| 211 | +
|
| 212 | + Returns |
| 213 | + ------- |
| 214 | + translated_argstr : str |
| 215 | + The translated string. |
| 216 | +
|
| 217 | + Examples |
| 218 | + -------- |
| 219 | + >>> non_ascii_to_octal("•‰“”±°ÿ") |
| 220 | + '\\31\\214\\216\\217\\261\\260\\377' |
| 221 | + >>> non_ascii_to_octal("αζΔΩ∑π∇") |
| 222 | + '@~\\141@~@~\\172@~@~\\104@~@~\\127@~@~\\345@~@~\\160@~@~\\321@~' |
| 223 | + >>> non_ascii_to_octal("✁❞❡➾") |
| 224 | + '@%34%\\41@%%@%34%\\176@%%@%34%\\241@%%@%34%\\376@%%' |
| 225 | + >>> non_ascii_to_octal("ABC ±120° DEF α ♥") |
| 226 | + 'ABC \\261120\\260 DEF @~\\141@~ @%34%\\252@%%' |
| 227 | + """ |
| 228 | + # Dictionary mapping non-ASCII characters to octal codes |
| 229 | + mapping = {} |
| 230 | + |
| 231 | + # Adobe Symbol charset |
| 232 | + # References: |
| 233 | + # 1. https://en.wikipedia.org/wiki/Symbol_(typeface) |
| 234 | + # 2. https://unicode.org/Public/MAPPINGS/VENDORS/ADOBE/symbol.txt |
| 235 | + # Notes: |
| 236 | + # 1. \322 and \342 are "REGISTERED SIGN SERIF" and |
| 237 | + # "REGISTERED SIGN SANS SERIF" respectively, but only "REGISTERED SIGN" |
| 238 | + # is available in the unicode table. So both are mapped to |
| 239 | + # "REGISTERED SIGN". \323, \343, \324 and \344 also have the same |
| 240 | + # problem. |
| 241 | + # 2. Characters for \140, \275, \276 are incorrect. |
| 242 | + mapping.update( |
| 243 | + { |
| 244 | + c: "@~\\" + format(i, "o") + "@~" |
| 245 | + for c, i in zip( |
| 246 | + " !∀#∃%&∋()∗+,−./" # \04x-05x |
| 247 | + + "0123456789:;<=>?" # \06x-07x |
| 248 | + + "≅ΑΒΧΔΕΦΓΗΙϑΚΛΜΝΟ" # \10x-11x |
| 249 | + + "ΠΘΡΣΤΥςΩΞΨΖ[∴]⊥_" # \12x-13x |
| 250 | + + "αβχδεφγηιϕκλμνο" # \14x-15x |
| 251 | + + "πθρστυϖωξψζ{|}∼" # \16x-17x. \177 is undefined |
| 252 | + + "€ϒ′≤⁄∞ƒ♣♦♥♠↔←↑→↓" # \24x-\25x |
| 253 | + + "°±″≥×∝∂•÷≠≡≈…↵" # \26x-27x |
| 254 | + + "ℵℑℜ℘⊗⊕∅∩∪⊃⊇⊄⊂⊆∈∉" # \30x-31x |
| 255 | + + "∠∇®©™∏√⋅¬∧∨⇔⇐⇑⇒⇓" # \32x-33x |
| 256 | + + "◊〈®©™∑" # \34x-35x |
| 257 | + + "〉∫⌠⌡", # \36x-37x. \360 and \377 are undefined |
| 258 | + [*range(32, 127), *range(160, 240), *range(241, 255)], |
| 259 | + ) |
| 260 | + } |
| 261 | + ) |
| 262 | + |
| 263 | + # Adobe ZapfDingbats charset |
| 264 | + # References: |
| 265 | + # 1. https://en.wikipedia.org/wiki/Zapf_Dingbats |
| 266 | + # 2. https://unicode.org/Public/MAPPINGS/VENDORS/ADOBE/zdingbat.txt |
| 267 | + mapping.update( |
| 268 | + { |
| 269 | + c: "@%34%\\" + format(i, "o") + "@%%" |
| 270 | + for c, i in zip( |
| 271 | + " ✁✂✃✄☎✆✇✈✉☛☞✌✍✎✏" # \04x-\05x |
| 272 | + + "✐✑✒✓✔✕✖✗✘✙✚✛✜✝✞✟" # \06x-\07x |
| 273 | + + "✠✡✢✣✤✥✦✧★✩✪✫✬✭✮✯" # \10x-\11x |
| 274 | + + "✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿" # \12x-\13x |
| 275 | + + "❀❁❂❃❄❅❆❇❈❉❊❋●❍■❏" # \14x-\15x |
| 276 | + + "❐❑❒▲▼◆❖◗❘❙❚❛❜❝❞" # \16x-\17x. \177 is undefined |
| 277 | + + "❡❢❣❤❥❦❧♣♦♥♠①②③④" # \24x-\25x. \240 is undefined |
| 278 | + + "⑤⑥⑦⑧⑨⑩❶❷❸❹❺❻❼❽❾❿" # \26x-\27x |
| 279 | + + "➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏" # \30x-\31x |
| 280 | + + "➐➑➒➓➔→↔↕➘➙➚➛➜➝➞➟" # \32x-\33x |
| 281 | + + "➠➡➢➣➤➥➦➧➨➩➪➫➬➭➮➯" # \34x-\35x |
| 282 | + + "➱➲➳➴➵➶➷➸➹➺➻➼➽➾", # \36x-\37x. \360 and \377 are undefined |
| 283 | + [*range(32, 127), *range(161, 240), *range(241, 255)], |
| 284 | + ) |
| 285 | + } |
| 286 | + ) |
| 287 | + |
| 288 | + # Adobe ISOLatin1+ charset (i.e., ISO-8859-1 with extensions) |
| 289 | + # References: |
| 290 | + # 1. https://en.wikipedia.org/wiki/ISO/IEC_8859-1 |
| 291 | + # 2. https://docs.generic-mapping-tools.org/dev/cookbook/octal-codes.html |
| 292 | + # 3. https://www.adobe.com/jp/print/postscript/pdfs/PLRM.pdf |
| 293 | + mapping.update( |
| 294 | + { |
| 295 | + c: "\\" + format(i, "o") |
| 296 | + for c, i in zip( |
| 297 | + "•…™—–fiž" # \03x. \030 is undefined |
| 298 | + + "š" # \177 |
| 299 | + + "Œ†‡Ł⁄‹Š›œŸŽł‰„“”" # \20x-\21x |
| 300 | + + "ı`´ˆ˜¯˘˙¨‚˚¸'˝˛ˇ", # \22x-\23x |
| 301 | + [*range(25, 32), *range(127, 160)], |
| 302 | + ) |
| 303 | + } |
| 304 | + ) |
| 305 | + # \240-\377 |
| 306 | + mapping.update({chr(i): "\\" + format(i, "o") for i in range(160, 256)}) |
| 307 | + |
| 308 | + # Remove any printable characters |
| 309 | + mapping = {k: v for k, v in mapping.items() if k not in string.printable} |
| 310 | + return argstr.translate(str.maketrans(mapping)) |
| 311 | + |
| 312 | + |
199 | 313 | def build_arg_string(kwdict, confdict=None, infile=None, outfile=None): |
200 | 314 | r""" |
201 | 315 | Convert keyword dictionaries and input/output files into a GMT argument |
@@ -318,7 +432,7 @@ def build_arg_string(kwdict, confdict=None, infile=None, outfile=None): |
318 | 432 | gmt_args = [str(infile)] + gmt_args |
319 | 433 | if outfile: |
320 | 434 | gmt_args.append("->" + str(outfile)) |
321 | | - return " ".join(gmt_args) |
| 435 | + return non_ascii_to_octal(" ".join(gmt_args)) |
322 | 436 |
|
323 | 437 |
|
324 | 438 | def is_nonstr_iter(value): |
|
0 commit comments