#!/usr/bin/python # -*- coding: utf-8 -*- # Generate indexes files for the Crep's chordbook compilation. This is # a replacement for the original makeindex program written in C that # produces an index file (.sbx) from a file generated by the latex # compilation of the songbook (.sxd). # # Usage : songbook-makeindex.py src # src is the .sxd file generated by latex # import sys import re import locale import warnings # Pattern set to ignore latex command in title prefix keywordPattern = re.compile(r"^%(\w+)\s?(.*)$") firstLetterPattern = re.compile(r"^(?:\{?\\\w+\}?)*[^\w]*(\w)") iecPattern = re.compile(r"\IeC {\\(.*?)}") replacePattern = { '`A': 'À', '`a': 'à', '^a': 'â', "'a": 'á', "~a": 'ã', 'oe': 'œ', "'e" : 'é', "`e" : 'è', "^e" : 'ê', '"e' : 'ë', "'E" : 'É', "`E" : 'È', "'o" : 'ó', "^o" : 'ô', r'"\i' : 'i', r'^\i' : 'i', '"u' : 'ü', '`u' : 'ù', '`u' : 'ù', '~n' : 'ñ', "c C" : 'Ç', "c c" : 'ç', "textquoteright" : "'", } def sortkey(value): ''' From a title, return something usable for sorting. It handles locale (but don't forget to call locale.setlocale(locale.LC_ALL, '')). It also try to handle the sort with crappy latex escape sequences. Some chars may not be handled by this function, so add them to *replacePattern* dictionnary. ''' def repl(match): try: return replacePattern[match.group(1).strip()] except KeyError: warnings.warn("Error, no match to replace %s in %s. You should add it in the coresponding table in title_sort.py" % (match.group(0), match.group(1))) return locale.strxfrm(iecPattern.sub(repl, value).replace(' ', 'A')) def processSXDEntry(tab): return (tab[0], tab[1], tab[2]) def processSXD(filename): file = open(filename) data = [] for line in file: data.append(line.strip()) file.close() type = data[0] i = 1 idx = index() if len(data) > 1: while data[i].startswith('%'): keywords = keywordPattern.match(data[i]).groups() idx.keyword(keywords[0],keywords[1]) i += 1 idx.compileKeywords() for i in range(i,len(data),3): entry = processSXDEntry(data[i:i+3]) idx.add(entry[0],entry[1],entry[2]) return idx class index: data = dict() keywords = dict() def filter(self, key): letter = firstLetterPattern.match(key).group(1) if re.match('\d',letter): letter = '0-9' return (letter.upper(), key) def keyword(self, key, word): if not self.keywords.has_key(key): self.keywords[key] = [] self.keywords[key].append(word) def compileKeywords(self): self.prefix_patterns = [] if 'prefix' in self.keywords: for prefix in self.keywords['prefix']: self.prefix_patterns.append(re.compile(r"^(%s)(\b|\\)(\s*.*)$" % prefix)) def add(self, key, number, link): for pattern in self.prefix_patterns: match = pattern.match(key) if match: key = "%s (%s)" % (match.group(2) + match.group(3), match.group(1)) break # Only one match per key (first, key) = self.filter(key) if not self.data.has_key(first): self.data[first] = dict() if not self.data[first].has_key(key): self.data[first][key] = [] self.data[first][key].append({'num':number, 'link':link}) def refToStr(self, ref): if sys.version_info >= (2,6): return '\\hyperlink{{{0[link]}}}{{{0[num]}}}'.format(ref) else: return '\\hyperlink{%(link)s}{%(num)s}' % ref def entryToStr(self, key, entry): if sys.version_info >= (2,6): return '\\idxentry{{{0}}}{{{1}}}\n'.format(key, '\\\\'.join(map(self.refToStr, entry))) else: return '\\idxentry{%s}{%s}\n' % (key, '\\\\'.join(map(self.refToStr, entry))) def idxBlockToStr(self, letter, entries): str = '\\begin{idxblock}{'+letter+'}'+'\n' for key in sorted(entries.keys(), key=sortkey): str += self.entryToStr(key, entries[key]) str += '\\end{idxblock}'+'\n' return str def entriesToStr(self): str = "" for letter in sorted(self.data.keys()): str += self.idxBlockToStr(letter, self.data[letter]) return str