matplotlib/matplotlib — pull request #1967 by mdboom (2013-05-03 13:23:08+00:00)
Title: svg double hyphen in plot title --

a double hyphen in plot title breaks the svg output because the double hyphen `--` gets included in a xml comment, breaking it

minimal example:

import matplotlib.pyplot as plt
plt.plot([0,1])
plt.title('--')
plt.savefig( 'a.svg', format='svg' )
plt.savefig( 'a.png', format='png' )

now try and open svg output it with firefox and it will point at the error line, 479 in version 1.2.1. which contains:

but xml comments cannot contain ``--``

I could not find in the stdlib a standard way to escape/unescape double hyphens, but if anyone does, we should use it.

if an standard way does not exist, my proposed solution is: replace `--` with something else in the svg comments. I suggest

- replace all occurrences of `--` with `-.-`, where `.` is any literal character
- replace all occurrences of `-.-` with `-..-`
- `-..-` with `-...-`

and that this be done in an overlapping manner:

- `---` becomes `-.-.-`

This can be achieved with the following class:

import re

class XmlCommentEscaper:
"""Escapes and unescapes ``--`` in xml comments so that they are not broken."""

def __init__(self):
self.escape_xml_comment = re.compile( r'-(\.*)(?=-)')

def escape(self,comment):
"""
>>> XmlCommentEscaper().escape('--')
'-.-'
>>> XmlCommentEscaper().escape('-- --')
'-.- -.-'

multiple:

>>> XmlCommentEscaper().escape('-.-')
'-..-'
>>> XmlCommentEscaper().escape('-..-')
'-...-'
>>> XmlCommentEscaper().escape('-...-')
'-....-'

overlap:

>>> XmlCommentEscaper().escape('---')
'-.-.-'
>>> XmlCommentEscaper().escape('----')
'-.-.-.-'
>>> XmlCommentEscaper().escape('-.--')
'-..-.-'

non matches:

>>> XmlCommentEscaper().escape('-.')
'-.'
>>> XmlCommentEscaper().escape('.-')
'.-'
"""
return self.escape_xml_comment.sub( lambda m: '-' + m.group(1) + '.', comment )

def unescape(self,comment):
"""
>>> XmlCommentEscaper().unescape('-.-')
'--'
>>> XmlCommentEscaper().unescape('-.- -.-')
'-- --'

multiple:

>>> XmlCommentEscaper().unescape('-..-')
'-.-'
>>> XmlCommentEscaper().unescape('-...-')
'-..-'
>>> XmlCommentEscaper().unescape('-....-')
'-...-'

overlap:

>>> XmlCommentEscaper().unescape('-.-.-')
'---'
>>> XmlCommentEscaper().unescape('-.-.-.-')
'----'
>>> XmlCommentEscaper().unescape('-..-.-')
'-.--'

non matches:

>>> XmlCommentEscaper().unescape('--')
'--'
>>> XmlCommentEscaper().unescape('-.')
'-.'
>>> XmlCommentEscaper().unescape('.-')
'.-'
"""
return self.escape_xml_comment.sub( lambda m: '-' + m.group(1)[1:], comment )

if __name__ == "__main__":
import doctest
doctest.testmod()

I just don't know exactly where to plug this, but it should take 5 mins for someone who knows the svg ``savefig`` architecture.