Mercurial > dottes
diff abcfield.py @ 586:daa3b76bd11f
More abcfield.py updates and mark it Python 3.
- Move title fixups into Python.
- Move key display name expansion into Python.
- Add Dottes-specific header continuation line format. None of the usual
tools appears to support the official +: continuation.
author | Jim Hague <jim.hague@acm.org> |
---|---|
date | Mon, 31 Oct 2016 23:48:45 +0000 |
parents | 696c461c8dc0 |
children | afc031477784 |
line wrap: on
line diff
--- a/abcfield.py Mon Oct 31 23:45:00 2016 +0000 +++ b/abcfield.py Mon Oct 31 23:48:45 2016 +0000 @@ -1,8 +1,20 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Extact a text field (title, by default) from a .abc file, and print it out # with any ABC accented characters converted to HTML (default) or Latex. -# Recognise continuation fields and print those too. +# +# Optionally rearrange a field into display format: +# * In Title fields, change 'sort' form such as 'Exploding Potato, The' +# to display format 'The Exploding Potato'. +# * In Key fields, translate the ABC key representation to full text, +# e.g. G#dor becomes G# Dorian. +# +# Recognise continuation header fields and print those too. The ABC standard +# defines continuation fields as starting ':+'. Regrettably none of the tools +# I am using the Booke recognise that syntax, so I am adopting a Booke +# convention of '<header>:+' *also* being a continuation. Note that a +# continuation is a distinct line in the field value; the value has a line +# break between it and the previous line. # import optparse @@ -87,7 +99,18 @@ "ss" : ("ß", "\\ss"), } -def convertField(t, options): +abckeys = { + "m": "Minor", + "min": "Minor", + "mix": "Mixolydian", + "dor": "Dorian", + "phr": "Phrygian", + "lyd": "Lydian", + "loc": "Locrian", +} + +# Convert ABC accented chars to HTML entities or LaTex. +def convertAccents(t, latex=False): res = "" while True: p = t.partition('\\') @@ -97,66 +120,121 @@ abc = p[2][0:2] t = p[2][2:] if abc in accentedletters: - if options.html: + if latex: + res += accentedletters[abc][1] + else: res += accentedletters[abc][0] - else: - res += accentedletters[abc][1] else: res += "\\" + abc return res -def process(inf, options): - n = options.index - found = False +# Convert Title fields from sort to display, so Bat, The->The Bat. +def convertTitleToDisplay(t): + p = t.rpartition(',') + if p[1] == "": + return t + else: + return p[2].strip() + " " + p[0].strip() + +# Convert Key field from ABC to display, so G#dor->G# Dorian. +def convertKeyToDisplay(t): + letter = t[0].upper() + accidental = "" + mode = "" + try: + accidental = t[1] + if accidental == '#' or accidental == 'b': + mode = t[2:] + else: + accidental = "" + mode = t[1:] + except IndexError: + pass + mode = mode.strip().lower() + return letter + accidental + ' ' + abckeys.get(mode, "Major") + +# Return the raw text for a given field. Optionally the nth field is taken, +# or the field data must start with a designated string to be recognised. +def getFieldText(inf, field, n = 1, starts = None): + res = None for line in inf: line = line.strip() if len(line) > 2 and line[1] == ':': - if found: - if line[0] != '+': + if line[0] == "+" or (line[0] == field and line[2] == "+"): + if not res: + continue + if line[0] == "+": + line = line[2:] + else: + line = line[3:] + res = res + '\n' + line.strip() + else: + if res: break - line = line[2:].strip() - elif line[0] == options.field: - if n > 1: - n = n - 1 - continue - else: + if line[0] == field: line = line[2:].strip() - if len(options.starts) > 0: - if line.find(options.starts) == 0: - line = line[len(options.starts):].strip() - else: + if starts: + if line.find(starts) != 0: continue - else: - continue - found = True - print(convertField(line, options)) - return found + line = line[len(starts):].strip() + if n > 1: + n = n - 1 + continue + res = line + return res + +# Return display text for a given field. +def getFieldDisplayText(inf, field, n = 1, starts = None, latex = False): + res = getFieldText(inf, field, n, starts) + if res: + if field.upper() == "T": + res = convertTitleToDisplay(res) + elif field.upper() == "K": + res = convertKeyToDisplay(res) + res = convertAccents(res, latex) + return res -parser = optparse.OptionParser(usage="usage: %prog [options] [filename]\n\n" - " Extract field data from ABC file.") -parser.add_option("-f", "--field", dest="field", default="T", - help="extract the field FIELD", metavar="FIELD") -parser.add_option("-l", "--latex", dest="latex", - action="store_true", default=False, - help="convert special characters for LaTeX") -parser.add_option("-n", "--index", dest="index", - action="store", type="int", default=1, - help="report INDEXth value [default: %default]", - metavar="INDEX") -parser.add_option("-s", "--starts", dest="starts", - action="store", type="string", default="", - help="report only if line starts CONTENT and remove CONTENT", - metavar="CONTENT") -(options, args) = parser.parse_args() +if __name__ == "__main__": + def process(inf, options): + if options.display: + line = getFieldDisplayText(inf, options.field, options.index, options.starts, options.latex) + else: + line = getFieldText(inf, options.field, options.index, options.starts) + if line: + print(line) + return True + else: + return False -res = False -if len(args) > 0: - for arg in args: - try: - inf = open(arg, "r") - res = res or process(inf, options) - finally: - inf.close() -else: - res = process(sys.stdin, options) -sys.exit(int(not res)) + # execute only if run as a script + parser = optparse.OptionParser(usage="usage: %prog [options] [filename]\n\n" + " Extract field data from ABC file.") + parser.add_option("-f", "--field", dest="field", default="T", + help="extract the field FIELD", metavar="FIELD") + parser.add_option("-l", "--latex", dest="latex", + action="store_true", default=False, + help="convert special characters for LaTeX") + parser.add_option("-d", "--display", dest="display", + action="store_true", default=False, + help="convert to display text") + parser.add_option("-n", "--index", dest="index", + action="store", type="int", default=1, + help="report INDEXth value [default: %default]", + metavar="INDEX") + parser.add_option("-s", "--starts", dest="starts", + action="store", type="string", default=None, + help="report only if line starts CONTENT and remove CONTENT", + metavar="CONTENT") + (options, args) = parser.parse_args() + + res = False + if len(args) > 0: + for arg in args: + try: + inf = open(arg, "r") + res = res or process(inf, options) + finally: + inf.close() + else: + res = process(sys.stdin, options) + sys.exit(int(not res))