Initial commit

This commit is contained in:
Senad Uka
2019-11-17 12:44:16 +01:00
parent e41eae7301
commit a3ef27c7a0
4894 changed files with 1771218 additions and 0 deletions

View File

@@ -0,0 +1,795 @@
# coding: utf-8
# $Id: __init__.py 8295 2019-07-24 09:22:01Z grubert $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
"""
Miscellaneous utilities for the documentation utilities.
"""
__docformat__ = 'reStructuredText'
import sys
import os
import os.path
import re
import itertools
import warnings
import unicodedata
from docutils import ApplicationError, DataError, __version_info__
from docutils import nodes
from docutils.nodes import unescape
import docutils.io
from docutils.utils.error_reporting import ErrorOutput, SafeString
class SystemMessage(ApplicationError):
def __init__(self, system_message, level):
Exception.__init__(self, system_message.astext())
self.level = level
class SystemMessagePropagation(ApplicationError): pass
class Reporter:
"""
Info/warning/error reporter and ``system_message`` element generator.
Five levels of system messages are defined, along with corresponding
methods: `debug()`, `info()`, `warning()`, `error()`, and `severe()`.
There is typically one Reporter object per process. A Reporter object is
instantiated with thresholds for reporting (generating warnings) and
halting processing (raising exceptions), a switch to turn debug output on
or off, and an I/O stream for warnings. These are stored as instance
attributes.
When a system message is generated, its level is compared to the stored
thresholds, and a warning or error is generated as appropriate. Debug
messages are produced if the stored debug switch is on, independently of
other thresholds. Message output is sent to the stored warning stream if
not set to ''.
The Reporter class also employs a modified form of the "Observer" pattern
[GoF95]_ to track system messages generated. The `attach_observer` method
should be called before parsing, with a bound method or function which
accepts system messages. The observer can be removed with
`detach_observer`, and another added in its place.
.. [GoF95] Gamma, Helm, Johnson, Vlissides. *Design Patterns: Elements of
Reusable Object-Oriented Software*. Addison-Wesley, Reading, MA, USA,
1995.
"""
levels = 'DEBUG INFO WARNING ERROR SEVERE'.split()
"""List of names for system message levels, indexed by level."""
# system message level constants:
(DEBUG_LEVEL,
INFO_LEVEL,
WARNING_LEVEL,
ERROR_LEVEL,
SEVERE_LEVEL) = list(range(5))
def __init__(self, source, report_level, halt_level, stream=None,
debug=False, encoding=None, error_handler='backslashreplace'):
"""
:Parameters:
- `source`: The path to or description of the source data.
- `report_level`: The level at or above which warning output will
be sent to `stream`.
- `halt_level`: The level at or above which `SystemMessage`
exceptions will be raised, halting execution.
- `debug`: Show debug (level=0) system messages?
- `stream`: Where warning output is sent. Can be file-like (has a
``.write`` method), a string (file name, opened for writing),
'' (empty string) or `False` (for discarding all stream messages)
or `None` (implies `sys.stderr`; default).
- `encoding`: The output encoding.
- `error_handler`: The error handler for stderr output encoding.
"""
self.source = source
"""The path to or description of the source data."""
self.error_handler = error_handler
"""The character encoding error handler."""
self.debug_flag = debug
"""Show debug (level=0) system messages?"""
self.report_level = report_level
"""The level at or above which warning output will be sent
to `self.stream`."""
self.halt_level = halt_level
"""The level at or above which `SystemMessage` exceptions
will be raised, halting execution."""
if not isinstance(stream, ErrorOutput):
stream = ErrorOutput(stream, encoding, error_handler)
self.stream = stream
"""Where warning output is sent."""
self.encoding = encoding or getattr(stream, 'encoding', 'ascii')
"""The output character encoding."""
self.observers = []
"""List of bound methods or functions to call with each system_message
created."""
self.max_level = -1
"""The highest level system message generated so far."""
def set_conditions(self, category, report_level, halt_level,
stream=None, debug=False):
warnings.warn('docutils.utils.Reporter.set_conditions deprecated; '
'set attributes via configuration settings or directly',
DeprecationWarning, stacklevel=2)
self.report_level = report_level
self.halt_level = halt_level
if not isinstance(stream, ErrorOutput):
stream = ErrorOutput(stream, self.encoding, self.error_handler)
self.stream = stream
self.debug_flag = debug
def attach_observer(self, observer):
"""
The `observer` parameter is a function or bound method which takes one
argument, a `nodes.system_message` instance.
"""
self.observers.append(observer)
def detach_observer(self, observer):
self.observers.remove(observer)
def notify_observers(self, message):
for observer in self.observers:
observer(message)
def system_message(self, level, message, *children, **kwargs):
"""
Return a system_message object.
Raise an exception or generate a warning if appropriate.
"""
# `message` can be a `string`, `unicode`, or `Exception` instance.
if isinstance(message, Exception):
message = SafeString(message)
attributes = kwargs.copy()
if 'base_node' in kwargs:
source, line = get_source_line(kwargs['base_node'])
del attributes['base_node']
if source is not None:
attributes.setdefault('source', source)
if line is not None:
attributes.setdefault('line', line)
# assert source is not None, "node has line- but no source-argument"
if not 'source' in attributes: # 'line' is absolute line number
try: # look up (source, line-in-source)
source, line = self.get_source_and_line(attributes.get('line'))
# print "locator lookup", kwargs.get('line'), "->", source, line
except AttributeError:
source, line = None, None
if source is not None:
attributes['source'] = source
if line is not None:
attributes['line'] = line
# assert attributes['line'] is not None, (message, kwargs)
# assert attributes['source'] is not None, (message, kwargs)
attributes.setdefault('source', self.source)
msg = nodes.system_message(message, level=level,
type=self.levels[level],
*children, **attributes)
if self.stream and (level >= self.report_level
or self.debug_flag and level == self.DEBUG_LEVEL
or level >= self.halt_level):
self.stream.write(msg.astext() + '\n')
if level >= self.halt_level:
raise SystemMessage(msg, level)
if level > self.DEBUG_LEVEL or self.debug_flag:
self.notify_observers(msg)
self.max_level = max(level, self.max_level)
return msg
def debug(self, *args, **kwargs):
"""
Level-0, "DEBUG": an internal reporting issue. Typically, there is no
effect on the processing. Level-0 system messages are handled
separately from the others.
"""
if self.debug_flag:
return self.system_message(self.DEBUG_LEVEL, *args, **kwargs)
def info(self, *args, **kwargs):
"""
Level-1, "INFO": a minor issue that can be ignored. Typically there is
no effect on processing, and level-1 system messages are not reported.
"""
return self.system_message(self.INFO_LEVEL, *args, **kwargs)
def warning(self, *args, **kwargs):
"""
Level-2, "WARNING": an issue that should be addressed. If ignored,
there may be unpredictable problems with the output.
"""
return self.system_message(self.WARNING_LEVEL, *args, **kwargs)
def error(self, *args, **kwargs):
"""
Level-3, "ERROR": an error that should be addressed. If ignored, the
output will contain errors.
"""
return self.system_message(self.ERROR_LEVEL, *args, **kwargs)
def severe(self, *args, **kwargs):
"""
Level-4, "SEVERE": a severe error that must be addressed. If ignored,
the output will contain severe errors. Typically level-4 system
messages are turned into exceptions which halt processing.
"""
return self.system_message(self.SEVERE_LEVEL, *args, **kwargs)
class ExtensionOptionError(DataError): pass
class BadOptionError(ExtensionOptionError): pass
class BadOptionDataError(ExtensionOptionError): pass
class DuplicateOptionError(ExtensionOptionError): pass
def extract_extension_options(field_list, options_spec):
"""
Return a dictionary mapping extension option names to converted values.
:Parameters:
- `field_list`: A flat field list without field arguments, where each
field body consists of a single paragraph only.
- `options_spec`: Dictionary mapping known option names to a
conversion function such as `int` or `float`.
:Exceptions:
- `KeyError` for unknown option names.
- `ValueError` for invalid option values (raised by the conversion
function).
- `TypeError` for invalid option value types (raised by conversion
function).
- `DuplicateOptionError` for duplicate options.
- `BadOptionError` for invalid fields.
- `BadOptionDataError` for invalid option data (missing name,
missing data, bad quotes, etc.).
"""
option_list = extract_options(field_list)
option_dict = assemble_option_dict(option_list, options_spec)
return option_dict
def extract_options(field_list):
"""
Return a list of option (name, value) pairs from field names & bodies.
:Parameter:
`field_list`: A flat field list, where each field name is a single
word and each field body consists of a single paragraph only.
:Exceptions:
- `BadOptionError` for invalid fields.
- `BadOptionDataError` for invalid option data (missing name,
missing data, bad quotes, etc.).
"""
option_list = []
for field in field_list:
if len(field[0].astext().split()) != 1:
raise BadOptionError(
'extension option field name may not contain multiple words')
name = str(field[0].astext().lower())
body = field[1]
if len(body) == 0:
data = None
elif len(body) > 1 or not isinstance(body[0], nodes.paragraph) \
or len(body[0]) != 1 or not isinstance(body[0][0], nodes.Text):
raise BadOptionDataError(
'extension option field body may contain\n'
'a single paragraph only (option "%s")' % name)
else:
data = body[0][0].astext()
option_list.append((name, data))
return option_list
def assemble_option_dict(option_list, options_spec):
"""
Return a mapping of option names to values.
:Parameters:
- `option_list`: A list of (name, value) pairs (the output of
`extract_options()`).
- `options_spec`: Dictionary mapping known option names to a
conversion function such as `int` or `float`.
:Exceptions:
- `KeyError` for unknown option names.
- `DuplicateOptionError` for duplicate options.
- `ValueError` for invalid option values (raised by conversion
function).
- `TypeError` for invalid option value types (raised by conversion
function).
"""
options = {}
for name, value in option_list:
convertor = options_spec[name] # raises KeyError if unknown
if convertor is None:
raise KeyError(name) # or if explicitly disabled
if name in options:
raise DuplicateOptionError('duplicate option "%s"' % name)
try:
options[name] = convertor(value)
except (ValueError, TypeError) as detail:
raise detail.__class__('(option: "%s"; value: %r)\n%s'
% (name, value, ' '.join(detail.args)))
return options
class NameValueError(DataError): pass
def decode_path(path):
"""
Ensure `path` is Unicode. Return `nodes.reprunicode` object.
Decode file/path string in a failsave manner if not already done.
"""
# see also http://article.gmane.org/gmane.text.docutils.user/2905
if isinstance(path, str):
return path
try:
path = path.decode(sys.getfilesystemencoding(), 'strict')
except AttributeError: # default value None has no decode method
return nodes.reprunicode(path)
except UnicodeDecodeError:
try:
path = path.decode('utf-8', 'strict')
except UnicodeDecodeError:
path = path.decode('ascii', 'replace')
return nodes.reprunicode(path)
def extract_name_value(line):
"""
Return a list of (name, value) from a line of the form "name=value ...".
:Exception:
`NameValueError` for invalid input (missing name, missing data, bad
quotes, etc.).
"""
attlist = []
while line:
equals = line.find('=')
if equals == -1:
raise NameValueError('missing "="')
attname = line[:equals].strip()
if equals == 0 or not attname:
raise NameValueError(
'missing attribute name before "="')
line = line[equals+1:].lstrip()
if not line:
raise NameValueError(
'missing value after "%s="' % attname)
if line[0] in '\'"':
endquote = line.find(line[0], 1)
if endquote == -1:
raise NameValueError(
'attribute "%s" missing end quote (%s)'
% (attname, line[0]))
if len(line) > endquote + 1 and line[endquote + 1].strip():
raise NameValueError(
'attribute "%s" end quote (%s) not followed by '
'whitespace' % (attname, line[0]))
data = line[1:endquote]
line = line[endquote+1:].lstrip()
else:
space = line.find(' ')
if space == -1:
data = line
line = ''
else:
data = line[:space]
line = line[space+1:].lstrip()
attlist.append((attname.lower(), data))
return attlist
def new_reporter(source_path, settings):
"""
Return a new Reporter object.
:Parameters:
`source` : string
The path to or description of the source text of the document.
`settings` : optparse.Values object
Runtime settings.
"""
reporter = Reporter(
source_path, settings.report_level, settings.halt_level,
stream=settings.warning_stream, debug=settings.debug,
encoding=settings.error_encoding,
error_handler=settings.error_encoding_error_handler)
return reporter
def new_document(source_path, settings=None):
"""
Return a new empty document object.
:Parameters:
`source_path` : string
The path to or description of the source text of the document.
`settings` : optparse.Values object
Runtime settings. If none are provided, a default core set will
be used. If you will use the document object with any Docutils
components, you must provide their default settings as well. For
example, if parsing, at least provide the parser settings,
obtainable as follows::
settings = docutils.frontend.OptionParser(
components=(docutils.parsers.rst.Parser,)
).get_default_values()
"""
from docutils import frontend
if settings is None:
settings = frontend.OptionParser().get_default_values()
source_path = decode_path(source_path)
reporter = new_reporter(source_path, settings)
document = nodes.document(settings, reporter, source=source_path)
document.note_source(source_path, -1)
return document
def clean_rcs_keywords(paragraph, keyword_substitutions):
if len(paragraph) == 1 and isinstance(paragraph[0], nodes.Text):
textnode = paragraph[0]
for pattern, substitution in keyword_substitutions:
match = pattern.search(textnode)
if match:
paragraph[0] = nodes.Text(pattern.sub(substitution, textnode))
return
def relative_path(source, target):
"""
Build and return a path to `target`, relative to `source` (both files).
If there is no common prefix, return the absolute path to `target`.
"""
source_parts = os.path.abspath(source or type(target)('dummy_file')
).split(os.sep)
target_parts = os.path.abspath(target).split(os.sep)
# Check first 2 parts because '/dir'.split('/') == ['', 'dir']:
if source_parts[:2] != target_parts[:2]:
# Nothing in common between paths.
# Return absolute path, using '/' for URLs:
return '/'.join(target_parts)
source_parts.reverse()
target_parts.reverse()
while (source_parts and target_parts
and source_parts[-1] == target_parts[-1]):
# Remove path components in common:
source_parts.pop()
target_parts.pop()
target_parts.reverse()
parts = ['..'] * (len(source_parts) - 1) + target_parts
return '/'.join(parts)
def get_stylesheet_reference(settings, relative_to=None):
"""
Retrieve a stylesheet reference from the settings object.
Deprecated. Use get_stylesheet_list() instead to
enable specification of multiple stylesheets as a comma-separated
list.
"""
if settings.stylesheet_path:
assert not settings.stylesheet, (
'stylesheet and stylesheet_path are mutually exclusive.')
if relative_to == None:
relative_to = settings._destination
return relative_path(relative_to, settings.stylesheet_path)
else:
return settings.stylesheet
# Return 'stylesheet' or 'stylesheet_path' arguments as list.
#
# The original settings arguments are kept unchanged: you can test
# with e.g. ``if settings.stylesheet_path:``
#
# Differences to ``get_stylesheet_reference``:
# * return value is a list
# * no re-writing of the path (and therefore no optional argument)
# (if required, use ``utils.relative_path(source, target)``
# in the calling script)
def get_stylesheet_list(settings):
"""
Retrieve list of stylesheet references from the settings object.
"""
assert not (settings.stylesheet and settings.stylesheet_path), (
'stylesheet and stylesheet_path are mutually exclusive.')
stylesheets = settings.stylesheet_path or settings.stylesheet or []
# programmatically set default can be string or unicode:
if not isinstance(stylesheets, list):
stylesheets = [path.strip() for path in stylesheets.split(',')]
# expand relative paths if found in stylesheet-dirs:
return [find_file_in_dirs(path, settings.stylesheet_dirs)
for path in stylesheets]
def find_file_in_dirs(path, dirs):
"""
Search for `path` in the list of directories `dirs`.
Return the first expansion that matches an existing file.
"""
if os.path.isabs(path):
return path
for d in dirs:
if d == '.':
f = path
else:
d = os.path.expanduser(d)
f = os.path.join(d, path)
if os.path.exists(f):
return f
return path
def get_trim_footnote_ref_space(settings):
"""
Return whether or not to trim footnote space.
If trim_footnote_reference_space is not None, return it.
If trim_footnote_reference_space is None, return False unless the
footnote reference style is 'superscript'.
"""
if settings.trim_footnote_reference_space is None:
return hasattr(settings, 'footnote_references') and \
settings.footnote_references == 'superscript'
else:
return settings.trim_footnote_reference_space
def get_source_line(node):
"""
Return the "source" and "line" attributes from the `node` given or from
its closest ancestor.
"""
while node:
if node.source or node.line:
return node.source, node.line
node = node.parent
return None, None
def escape2null(text):
"""Return a string with escape-backslashes converted to nulls."""
parts = []
start = 0
while True:
found = text.find('\\', start)
if found == -1:
parts.append(text[start:])
return ''.join(parts)
parts.append(text[start:found])
parts.append('\x00' + text[found+1:found+2])
start = found + 2 # skip character after escape
# `unescape` definition moved to `nodes` to avoid circular import dependency.
def split_escaped_whitespace(text):
"""
Split `text` on escaped whitespace (null+space or null+newline).
Return a list of strings.
"""
strings = text.split('\x00 ')
strings = [string.split('\x00\n') for string in strings]
# flatten list of lists of strings to list of strings:
return list(itertools.chain(*strings))
def strip_combining_chars(text):
if isinstance(text, str) and sys.version_info < (3,0):
return text
return ''.join([c for c in text if not unicodedata.combining(c)])
def find_combining_chars(text):
"""Return indices of all combining chars in Unicode string `text`.
>>> from docutils.utils import find_combining_chars
>>> find_combining_chars(u'A t̆ab̆lĕ')
[3, 6, 9]
"""
if isinstance(text, str) and sys.version_info < (3,0):
return []
return [i for i,c in enumerate(text) if unicodedata.combining(c)]
def column_indices(text):
"""Indices of Unicode string `text` when skipping combining characters.
>>> from docutils.utils import column_indices
>>> column_indices(u'A t̆ab̆lĕ')
[0, 1, 2, 4, 5, 7, 8]
"""
# TODO: account for asian wide chars here instead of using dummy
# replacements in the tableparser?
string_indices = list(range(len(text)))
for index in find_combining_chars(text):
string_indices[index] = None
return [i for i in string_indices if i is not None]
east_asian_widths = {'W': 2, # Wide
'F': 2, # Full-width (wide)
'Na': 1, # Narrow
'H': 1, # Half-width (narrow)
'N': 1, # Neutral (not East Asian, treated as narrow)
'A': 1} # Ambiguous (s/b wide in East Asian context,
# narrow otherwise, but that doesn't work)
"""Mapping of result codes from `unicodedata.east_asian_widt()` to character
column widths."""
def column_width(text):
"""Return the column width of text.
Correct ``len(text)`` for wide East Asian and combining Unicode chars.
"""
if isinstance(text, str) and sys.version_info < (3,0):
return len(text)
width = sum([east_asian_widths[unicodedata.east_asian_width(c)]
for c in text])
# correction for combining chars:
width -= len(find_combining_chars(text))
return width
def uniq(L):
r = []
for item in L:
if not item in r:
r.append(item)
return r
def unique_combinations(items, n):
"""Return `itertools.combinations`."""
warnings.warn('docutils.utils.unique_combinations is deprecated; '
'use itertools.combinations directly.',
DeprecationWarning, stacklevel=2)
return itertools.combinations(items, n)
def normalize_language_tag(tag):
"""Return a list of normalized combinations for a `BCP 47` language tag.
Example:
>>> from docutils.utils import normalize_language_tag
>>> normalize_language_tag('de_AT-1901')
['de-at-1901', 'de-at', 'de-1901', 'de']
>>> normalize_language_tag('de-CH-x_altquot')
['de-ch-x-altquot', 'de-ch', 'de-x-altquot', 'de']
"""
# normalize:
tag = tag.lower().replace('-','_')
# split (except singletons, which mark the following tag as non-standard):
tag = re.sub(r'_([a-zA-Z0-9])_', r'_\1-', tag)
subtags = [subtag for subtag in tag.split('_')]
base_tag = (subtags.pop(0),)
# find all combinations of subtags
taglist = []
for n in range(len(subtags), 0, -1):
# for tags in unique_combinations(subtags, n):
for tags in itertools.combinations(subtags, n):
taglist.append('-'.join(base_tag+tags))
taglist += base_tag
return taglist
class DependencyList(object):
"""
List of dependencies, with file recording support.
Note that the output file is not automatically closed. You have
to explicitly call the close() method.
"""
def __init__(self, output_file=None, dependencies=[]):
"""
Initialize the dependency list, automatically setting the
output file to `output_file` (see `set_output()`) and adding
all supplied dependencies.
"""
self.set_output(output_file)
for i in dependencies:
self.add(i)
def set_output(self, output_file):
"""
Set the output file and clear the list of already added
dependencies.
`output_file` must be a string. The specified file is
immediately overwritten.
If output_file is '-', the output will be written to stdout.
If it is None, no file output is done when calling add().
"""
self.list = []
if output_file:
if output_file == '-':
of = None
else:
of = output_file
self.file = docutils.io.FileOutput(destination_path=of,
encoding='utf8', autoclose=False)
else:
self.file = None
def add(self, *filenames):
"""
If the dependency `filename` has not already been added,
append it to self.list and print it to self.file if self.file
is not None.
"""
for filename in filenames:
if not filename in self.list:
self.list.append(filename)
if self.file is not None:
self.file.write(filename+'\n')
def close(self):
"""
Close the output file.
"""
self.file.close()
self.file = None
def __repr__(self):
try:
output_file = self.file.name
except AttributeError:
output_file = None
return '%s(%r, %s)' % (self.__class__.__name__, output_file, self.list)
release_level_abbreviations = {
'alpha': 'a',
'beta': 'b',
'candidate': 'rc',
'final': '',}
def version_identifier(version_info=None):
"""
Return a version identifier string built from `version_info`, a
`docutils.VersionInfo` namedtuple instance or compatible tuple. If
`version_info` is not provided, by default return a version identifier
string based on `docutils.__version_info__` (i.e. the current Docutils
version).
"""
if version_info is None:
version_info = __version_info__
if version_info.micro:
micro = '.%s' % version_info.micro
else:
# 0 is omitted:
micro = ''
releaselevel = release_level_abbreviations[version_info.releaselevel]
if version_info.serial:
serial = version_info.serial
else:
# 0 is omitted:
serial = ''
if version_info.release:
dev = ''
else:
dev = '.dev'
version = '%s.%s%s%s%s%s' % (
version_info.major,
version_info.minor,
micro,
releaselevel,
serial,
dev)
return version

View File

@@ -0,0 +1,142 @@
#!/usr/bin/python
# coding: utf-8
"""Lexical analysis of formal languages (i.e. code) using Pygments."""
# :Author: Georg Brandl; Felix Wiemann; Günter Milde
# :Date: $Date: 2018-01-16 21:43:16 +0100 (Di, 16. Jän 2018) $
# :Copyright: This module has been placed in the public domain.
from docutils import ApplicationError
try:
from pkg_resources import DistributionNotFound as ResourceError
except (ImportError, RuntimeError):
class ResourceError(ApplicationError):
pass # stub
try:
import pygments
from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import _get_ttype_class
with_pygments = True
except (ImportError, SyntaxError): # pygments 2.0.1 fails with Py 3.1 and 3.2
with_pygments = False
# Filter the following token types from the list of class arguments:
unstyled_tokens = ['token', # Token (base token type)
'text', # Token.Text
''] # short name for Token and Text
# (Add, e.g., Token.Punctuation with ``unstyled_tokens += 'punctuation'``.)
class LexerError(ApplicationError):
pass
class Lexer(object):
"""Parse `code` lines and yield "classified" tokens.
Arguments
code -- string of source code to parse,
language -- formal language the code is written in,
tokennames -- either 'long', 'short', or '' (see below).
Merge subsequent tokens of the same token-type.
Iterating over an instance yields the tokens as ``(tokentype, value)``
tuples. The value of `tokennames` configures the naming of the tokentype:
'long': downcased full token type name,
'short': short name defined by pygments.token.STANDARD_TYPES
(= class argument used in pygments html output),
'none': skip lexical analysis.
"""
def __init__(self, code, language, tokennames='short'):
"""
Set up a lexical analyzer for `code` in `language`.
"""
self.code = code
self.language = language
self.tokennames = tokennames
self.lexer = None
# get lexical analyzer for `language`:
if language in ('', 'text') or tokennames == 'none':
return
if not with_pygments:
raise LexerError('Cannot analyze code. '
'Pygments package not found.')
try:
self.lexer = get_lexer_by_name(self.language)
except (pygments.util.ClassNotFound, ResourceError):
raise LexerError('Cannot analyze code. '
'No Pygments lexer found for "%s".' % language)
# self.lexer.add_filter('tokenmerge')
# Since version 1.2. (released Jan 01, 2010) Pygments has a
# TokenMergeFilter. # ``self.merge(tokens)`` in __iter__ could
# be replaced by ``self.lexer.add_filter('tokenmerge')`` in __init__.
# However, `merge` below also strips a final newline added by pygments.
#
# self.lexer.add_filter('tokenmerge')
def merge(self, tokens):
"""Merge subsequent tokens of same token-type.
Also strip the final newline (added by pygments).
"""
tokens = iter(tokens)
(lasttype, lastval) = next(tokens)
for ttype, value in tokens:
if ttype is lasttype:
lastval += value
else:
yield(lasttype, lastval)
(lasttype, lastval) = (ttype, value)
if lastval.endswith('\n'):
lastval = lastval[:-1]
if lastval:
yield(lasttype, lastval)
def __iter__(self):
"""Parse self.code and yield "classified" tokens.
"""
if self.lexer is None:
yield ([], self.code)
return
tokens = pygments.lex(self.code, self.lexer)
for tokentype, value in self.merge(tokens):
if self.tokennames == 'long': # long CSS class args
classes = str(tokentype).lower().split('.')
else: # short CSS class args
classes = [_get_ttype_class(tokentype)]
classes = [cls for cls in classes if cls not in unstyled_tokens]
yield (classes, value)
class NumberLines(object):
"""Insert linenumber-tokens at the start of every code line.
Arguments
tokens -- iterable of ``(classes, value)`` tuples
startline -- first line number
endline -- last line number
Iterating over an instance yields the tokens with a
``(['ln'], '<the line number>')`` token added for every code line.
Multi-line tokens are splitted."""
def __init__(self, tokens, startline, endline):
self.tokens = tokens
self.startline = startline
# pad linenumbers, e.g. endline == 100 -> fmt_str = '%3d '
self.fmt_str = '%%%dd ' % len(str(endline))
def __iter__(self):
lineno = self.startline
yield (['ln'], self.fmt_str % lineno)
for ttype, value in self.tokens:
lines = value.split('\n')
for line in lines[:-1]:
yield (ttype, line + '\n')
lineno += 1
yield (['ln'], self.fmt_str % lineno)
yield (ttype, lines[-1])

View File

@@ -0,0 +1,225 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# :Id: $Id: error_reporting.py 8119 2017-06-22 20:59:19Z milde $
# :Copyright: © 2011 Günter Milde.
# :License: Released under the terms of the `2-Clause BSD license`_, in short:
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.
# This file is offered as-is, without any warranty.
#
# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause
"""
Error reporting should be safe from encoding/decoding errors.
However, implicit conversions of strings and exceptions like
>>> u'%s world: %s' % ('H\xe4llo', Exception(u'H\xe4llo')
fail in some Python versions:
* In Python <= 2.6, ``unicode(<exception instance>)`` uses
`__str__` and fails with non-ASCII chars in`unicode` arguments.
(work around http://bugs.python.org/issue2517):
* In Python 2, unicode(<exception instance>) fails, with non-ASCII
chars in arguments. (Use case: in some locales, the errstr
argument of IOError contains non-ASCII chars.)
* In Python 2, str(<exception instance>) fails, with non-ASCII chars
in `unicode` arguments.
The `SafeString`, `ErrorString` and `ErrorOutput` classes handle
common exceptions.
"""
import sys, codecs
# Guess the locale's encoding.
# If no valid guess can be made, locale_encoding is set to `None`:
try:
import locale # module missing in Jython
except ImportError:
locale_encoding = None
else:
try:
locale_encoding = locale.getlocale()[1] or locale.getdefaultlocale()[1]
# locale.getpreferredencoding([do_setlocale=True|False])
# has side-effects | might return a wrong guess.
# (cf. Update 1 in http://stackoverflow.com/questions/4082645/using-python-2-xs-locale-module-to-format-numbers-and-currency)
except ValueError as error: # OS X may set UTF-8 without language code
# see http://bugs.python.org/issue18378
# and https://sourceforge.net/p/docutils/bugs/298/
if "unknown locale: UTF-8" in error.args:
locale_encoding = "UTF-8"
else:
locale_encoding = None
except: # any other problems determining the locale -> use None
locale_encoding = None
try:
codecs.lookup(locale_encoding or '') # None -> ''
except LookupError:
locale_encoding = None
class SafeString(object):
"""
A wrapper providing robust conversion to `str` and `unicode`.
"""
def __init__(self, data, encoding=None, encoding_errors='backslashreplace',
decoding_errors='replace'):
self.data = data
self.encoding = (encoding or getattr(data, 'encoding', None) or
locale_encoding or 'ascii')
self.encoding_errors = encoding_errors
self.decoding_errors = decoding_errors
def __str__(self):
try:
return str(self.data)
except UnicodeEncodeError:
if isinstance(self.data, Exception):
args = [str(SafeString(arg, self.encoding,
self.encoding_errors))
for arg in self.data.args]
return ', '.join(args)
if isinstance(self.data, str):
if sys.version_info > (3,0):
return self.data
else:
return self.data.encode(self.encoding,
self.encoding_errors)
raise
def __unicode__(self):
"""
Return unicode representation of `self.data`.
Try ``unicode(self.data)``, catch `UnicodeError` and
* if `self.data` is an Exception instance, work around
http://bugs.python.org/issue2517 with an emulation of
Exception.__unicode__,
* else decode with `self.encoding` and `self.decoding_errors`.
"""
try:
u = str(self.data)
if isinstance(self.data, EnvironmentError):
u = u.replace(": u'", ": '") # normalize filename quoting
return u
except UnicodeError as error: # catch ..Encode.. and ..Decode.. errors
if isinstance(self.data, EnvironmentError):
return "[Errno %s] %s: '%s'" % (self.data.errno,
SafeString(self.data.strerror, self.encoding,
self.decoding_errors),
SafeString(self.data.filename, self.encoding,
self.decoding_errors))
if isinstance(self.data, Exception):
args = [str(SafeString(arg, self.encoding,
decoding_errors=self.decoding_errors))
for arg in self.data.args]
return ', '.join(args)
if isinstance(error, UnicodeDecodeError):
return str(self.data, self.encoding, self.decoding_errors)
raise
class ErrorString(SafeString):
"""
Safely report exception type and message.
"""
def __str__(self):
return '%s: %s' % (self.data.__class__.__name__,
super(ErrorString, self).__str__())
def __unicode__(self):
return '%s: %s' % (self.data.__class__.__name__,
super(ErrorString, self).__unicode__())
class ErrorOutput(object):
"""
Wrapper class for file-like error streams with
failsave de- and encoding of `str`, `bytes`, `unicode` and
`Exception` instances.
"""
def __init__(self, stream=None, encoding=None,
encoding_errors='backslashreplace',
decoding_errors='replace'):
"""
:Parameters:
- `stream`: a file-like object,
a string (path to a file),
`None` (write to `sys.stderr`, default), or
evaluating to `False` (write() requests are ignored).
- `encoding`: `stream` text encoding. Guessed if None.
- `encoding_errors`: how to treat encoding errors.
"""
if stream is None:
stream = sys.stderr
elif not(stream):
stream = False
# if `stream` is a file name, open it
elif isinstance(stream, str):
stream = open(stream, 'w')
elif isinstance(stream, str):
stream = open(stream.encode(sys.getfilesystemencoding()), 'w')
self.stream = stream
"""Where warning output is sent."""
self.encoding = (encoding or getattr(stream, 'encoding', None) or
locale_encoding or 'ascii')
"""The output character encoding."""
self.encoding_errors = encoding_errors
"""Encoding error handler."""
self.decoding_errors = decoding_errors
"""Decoding error handler."""
def write(self, data):
"""
Write `data` to self.stream. Ignore, if self.stream is False.
`data` can be a `string`, `unicode`, or `Exception` instance.
"""
if self.stream is False:
return
if isinstance(data, Exception):
data = str(SafeString(data, self.encoding,
self.encoding_errors, self.decoding_errors))
try:
self.stream.write(data)
except UnicodeEncodeError:
self.stream.write(data.encode(self.encoding, self.encoding_errors))
except TypeError:
if isinstance(data, str): # passed stream may expect bytes
self.stream.write(data.encode(self.encoding,
self.encoding_errors))
return
if self.stream in (sys.stderr, sys.stdout):
self.stream.buffer.write(data) # write bytes to raw stream
else:
self.stream.write(str(data, self.encoding,
self.decoding_errors))
def close(self):
"""
Close the error-output stream.
Ignored if the stream is` sys.stderr` or `sys.stdout` or has no
close() method.
"""
if self.stream in (sys.stdout, sys.stderr):
return
try:
self.stream.close()
except AttributeError:
pass

View File

@@ -0,0 +1,48 @@
# :Id: $Id: __init__.py 7865 2015-04-12 10:06:43Z milde $
# :Author: Guenter Milde.
# :License: Released under the terms of the `2-Clause BSD license`_, in short:
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.
# This file is offered as-is, without any warranty.
#
# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause
"""
This is the Docutils (Python Documentation Utilities) "math" sub-package.
It contains various modules for conversion between different math formats
(LaTeX, MathML, HTML).
:math2html: LaTeX math -> HTML conversion from eLyXer
:latex2mathml: LaTeX math -> presentational MathML
:unichar2tex: Unicode character to LaTeX math translation table
:tex2unichar: LaTeX math to Unicode character translation dictionaries
:tex2mathml_extern: Wrapper for TeX -> MathML command line converters
"""
# helpers for Docutils math support
# =================================
def pick_math_environment(code, numbered=False):
"""Return the right math environment to display `code`.
The test simply looks for line-breaks (``\\``) outside environments.
Multi-line formulae are set with ``align``, one-liners with
``equation``.
If `numbered` evaluates to ``False``, the "starred" versions are used
to suppress numbering.
"""
# cut out environment content:
chunks = code.split(r'\begin{')
toplevel_code = ''.join([chunk.split(r'\end{')[-1]
for chunk in chunks])
if toplevel_code.find(r'\\') >= 0:
env = 'align'
else:
env = 'equation'
if not numbered:
env += '*'
return env

View File

@@ -0,0 +1,571 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# :Id: $Id: latex2mathml.py 7995 2016-12-10 17:50:59Z milde $
# :Copyright: © 2010 Günter Milde.
# Based on rst2mathml.py from the latex_math sandbox project
# © 2005 Jens Jørgen Mortensen
# :License: Released under the terms of the `2-Clause BSD license`_, in short:
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.
# This file is offered as-is, without any warranty.
#
# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause
"""Convert LaTex math code into presentational MathML"""
# Based on the `latex_math` sandbox project by Jens Jørgen Mortensen
import docutils.utils.math.tex2unichar as tex2unichar
# TeX spacing combining
over = {'acute': '\u00B4', # u'\u0301',
'bar': '\u00AF', # u'\u0304',
'breve': '\u02D8', # u'\u0306',
'check': '\u02C7', # u'\u030C',
'dot': '\u02D9', # u'\u0307',
'ddot': '\u00A8', # u'\u0308',
'dddot': '\u20DB',
'grave': '`', # u'\u0300',
'hat': '^', # u'\u0302',
'mathring': '\u02DA', # u'\u030A',
'overleftrightarrow': '\u20e1',
# 'overline': # u'\u0305',
'tilde': '\u02DC', # u'\u0303',
'vec': '\u20D7'}
Greek = { # Capital Greek letters: (upright in TeX style)
'Phi':'\u03a6', 'Xi':'\u039e', 'Sigma':'\u03a3',
'Psi':'\u03a8', 'Delta':'\u0394', 'Theta':'\u0398',
'Upsilon':'\u03d2', 'Pi':'\u03a0', 'Omega':'\u03a9',
'Gamma':'\u0393', 'Lambda':'\u039b'}
letters = tex2unichar.mathalpha
special = tex2unichar.mathbin # Binary symbols
special.update(tex2unichar.mathrel) # Relation symbols, arrow symbols
special.update(tex2unichar.mathord) # Miscellaneous symbols
special.update(tex2unichar.mathop) # Variable-sized symbols
special.update(tex2unichar.mathopen) # Braces
special.update(tex2unichar.mathclose) # Braces
special.update(tex2unichar.mathfence)
sumintprod = ''.join([special[symbol] for symbol in
['sum', 'int', 'oint', 'prod']])
functions = ['arccos', 'arcsin', 'arctan', 'arg', 'cos', 'cosh',
'cot', 'coth', 'csc', 'deg', 'det', 'dim',
'exp', 'gcd', 'hom', 'inf', 'ker', 'lg',
'lim', 'liminf', 'limsup', 'ln', 'log', 'max',
'min', 'Pr', 'sec', 'sin', 'sinh', 'sup',
'tan', 'tanh',
'injlim', 'varinjlim', 'varlimsup',
'projlim', 'varliminf', 'varprojlim']
mathbb = {
'A': '\U0001D538',
'B': '\U0001D539',
'C': '\u2102',
'D': '\U0001D53B',
'E': '\U0001D53C',
'F': '\U0001D53D',
'G': '\U0001D53E',
'H': '\u210D',
'I': '\U0001D540',
'J': '\U0001D541',
'K': '\U0001D542',
'L': '\U0001D543',
'M': '\U0001D544',
'N': '\u2115',
'O': '\U0001D546',
'P': '\u2119',
'Q': '\u211A',
'R': '\u211D',
'S': '\U0001D54A',
'T': '\U0001D54B',
'U': '\U0001D54C',
'V': '\U0001D54D',
'W': '\U0001D54E',
'X': '\U0001D54F',
'Y': '\U0001D550',
'Z': '\u2124',
}
mathscr = {
'A': '\U0001D49C',
'B': '\u212C', # bernoulli function
'C': '\U0001D49E',
'D': '\U0001D49F',
'E': '\u2130',
'F': '\u2131',
'G': '\U0001D4A2',
'H': '\u210B', # hamiltonian
'I': '\u2110',
'J': '\U0001D4A5',
'K': '\U0001D4A6',
'L': '\u2112', # lagrangian
'M': '\u2133', # physics m-matrix
'N': '\U0001D4A9',
'O': '\U0001D4AA',
'P': '\U0001D4AB',
'Q': '\U0001D4AC',
'R': '\u211B',
'S': '\U0001D4AE',
'T': '\U0001D4AF',
'U': '\U0001D4B0',
'V': '\U0001D4B1',
'W': '\U0001D4B2',
'X': '\U0001D4B3',
'Y': '\U0001D4B4',
'Z': '\U0001D4B5',
'a': '\U0001D4B6',
'b': '\U0001D4B7',
'c': '\U0001D4B8',
'd': '\U0001D4B9',
'e': '\u212F',
'f': '\U0001D4BB',
'g': '\u210A',
'h': '\U0001D4BD',
'i': '\U0001D4BE',
'j': '\U0001D4BF',
'k': '\U0001D4C0',
'l': '\U0001D4C1',
'm': '\U0001D4C2',
'n': '\U0001D4C3',
'o': '\u2134', # order of
'p': '\U0001D4C5',
'q': '\U0001D4C6',
'r': '\U0001D4C7',
's': '\U0001D4C8',
't': '\U0001D4C9',
'u': '\U0001D4CA',
'v': '\U0001D4CB',
'w': '\U0001D4CC',
'x': '\U0001D4CD',
'y': '\U0001D4CE',
'z': '\U0001D4CF',
}
negatables = {'=': '\u2260',
r'\in': '\u2209',
r'\equiv': '\u2262'}
# LaTeX to MathML translation stuff:
class math:
"""Base class for MathML elements."""
nchildren = 1000000
"""Required number of children"""
def __init__(self, children=None, inline=None):
"""math([children]) -> MathML element
children can be one child or a list of children."""
self.children = []
if children is not None:
if type(children) is list:
for child in children:
self.append(child)
else:
# Only one child:
self.append(children)
if inline is not None:
self.inline = inline
def __repr__(self):
if hasattr(self, 'children'):
return self.__class__.__name__ + '(%s)' % \
','.join([repr(child) for child in self.children])
else:
return self.__class__.__name__
def full(self):
"""Room for more children?"""
return len(self.children) >= self.nchildren
def append(self, child):
"""append(child) -> element
Appends child and returns self if self is not full or first
non-full parent."""
assert not self.full()
self.children.append(child)
child.parent = self
node = self
while node.full():
node = node.parent
return node
def delete_child(self):
"""delete_child() -> child
Delete last child and return it."""
child = self.children[-1]
del self.children[-1]
return child
def close(self):
"""close() -> parent
Close element and return first non-full element."""
parent = self.parent
while parent.full():
parent = parent.parent
return parent
def xml(self):
"""xml() -> xml-string"""
return self.xml_start() + self.xml_body() + self.xml_end()
def xml_start(self):
if not hasattr(self, 'inline'):
return ['<%s>' % self.__class__.__name__]
xmlns = 'http://www.w3.org/1998/Math/MathML'
if self.inline:
return ['<math xmlns="%s">' % xmlns]
else:
return ['<math xmlns="%s" mode="display">' % xmlns]
def xml_end(self):
return ['</%s>' % self.__class__.__name__]
def xml_body(self):
xml = []
for child in self.children:
xml.extend(child.xml())
return xml
class mrow(math):
def xml_start(self):
return ['\n<%s>' % self.__class__.__name__]
class mtable(math):
def xml_start(self):
return ['\n<%s>' % self.__class__.__name__]
class mtr(mrow): pass
class mtd(mrow): pass
class mx(math):
"""Base class for mo, mi, and mn"""
nchildren = 0
def __init__(self, data):
self.data = data
def xml_body(self):
return [self.data]
class mo(mx):
translation = {'<': '&lt;', '>': '&gt;'}
def xml_body(self):
return [self.translation.get(self.data, self.data)]
class mi(mx): pass
class mn(mx): pass
class msub(math):
nchildren = 2
class msup(math):
nchildren = 2
class msqrt(math):
nchildren = 1
class mroot(math):
nchildren = 2
class mfrac(math):
nchildren = 2
class msubsup(math):
nchildren = 3
def __init__(self, children=None, reversed=False):
self.reversed = reversed
math.__init__(self, children)
def xml(self):
if self.reversed:
## self.children[1:3] = self.children[2:0:-1]
self.children[1:3] = [self.children[2], self.children[1]]
self.reversed = False
return math.xml(self)
class mfenced(math):
translation = {'\\{': '{', '\\langle': '\u2329',
'\\}': '}', '\\rangle': '\u232A',
'.': ''}
def __init__(self, par):
self.openpar = par
math.__init__(self)
def xml_start(self):
open = self.translation.get(self.openpar, self.openpar)
close = self.translation.get(self.closepar, self.closepar)
return ['<mfenced open="%s" close="%s">' % (open, close)]
class mspace(math):
nchildren = 0
class mstyle(math):
def __init__(self, children=None, nchildren=None, **kwargs):
if nchildren is not None:
self.nchildren = nchildren
math.__init__(self, children)
self.attrs = kwargs
def xml_start(self):
return ['<mstyle '] + ['%s="%s"' % item
for item in list(self.attrs.items())] + ['>']
class mover(math):
nchildren = 2
def __init__(self, children=None, reversed=False):
self.reversed = reversed
math.__init__(self, children)
def xml(self):
if self.reversed:
self.children.reverse()
self.reversed = False
return math.xml(self)
class munder(math):
nchildren = 2
class munderover(math):
nchildren = 3
def __init__(self, children=None):
math.__init__(self, children)
class mtext(math):
nchildren = 0
def __init__(self, text):
self.text = text
def xml_body(self):
return [self.text]
def parse_latex_math(string, inline=True):
"""parse_latex_math(string [,inline]) -> MathML-tree
Returns a MathML-tree parsed from string. inline=True is for
inline math and inline=False is for displayed math.
tree is the whole tree and node is the current element."""
# Normalize white-space:
string = ' '.join(string.split())
if inline:
node = mrow()
tree = math(node, inline=True)
else:
node = mtd()
tree = math(mtable(mtr(node)), inline=False)
while len(string) > 0:
n = len(string)
c = string[0]
skip = 1 # number of characters consumed
if n > 1:
c2 = string[1]
else:
c2 = ''
## print n, string, c, c2, node.__class__.__name__
if c == ' ':
pass
elif c == '\\':
if c2 in '{}':
node = node.append(mo(c2))
skip = 2
elif c2 == ' ':
node = node.append(mspace())
skip = 2
elif c2 == ',': # TODO: small space
node = node.append(mspace())
skip = 2
elif c2.isalpha():
# We have a LaTeX-name:
i = 2
while i < n and string[i].isalpha():
i += 1
name = string[1:i]
node, skip = handle_keyword(name, node, string[i:])
skip += i
elif c2 == '\\':
# End of a row:
entry = mtd()
row = mtr(entry)
node.close().close().append(row)
node = entry
skip = 2
else:
raise SyntaxError(r'Syntax error: "%s%s"' % (c, c2))
elif c.isalpha():
node = node.append(mi(c))
elif c.isdigit():
node = node.append(mn(c))
elif c in "+-*/=()[]|<>,.!?':;@":
node = node.append(mo(c))
elif c == '_':
child = node.delete_child()
if isinstance(child, msup):
sub = msubsup(child.children, reversed=True)
elif isinstance(child, mo) and child.data in sumintprod:
sub = munder(child)
else:
sub = msub(child)
node.append(sub)
node = sub
elif c == '^':
child = node.delete_child()
if isinstance(child, msub):
sup = msubsup(child.children)
elif isinstance(child, mo) and child.data in sumintprod:
sup = mover(child)
elif (isinstance(child, munder) and
child.children[0].data in sumintprod):
sup = munderover(child.children)
else:
sup = msup(child)
node.append(sup)
node = sup
elif c == '{':
row = mrow()
node.append(row)
node = row
elif c == '}':
node = node.close()
elif c == '&':
entry = mtd()
node.close().append(entry)
node = entry
else:
raise SyntaxError(r'Illegal character: "%s"' % c)
string = string[skip:]
return tree
def handle_keyword(name, node, string):
skip = 0
if len(string) > 0 and string[0] == ' ':
string = string[1:]
skip = 1
if name == 'begin':
if not string.startswith('{matrix}'):
raise SyntaxError('Environment not supported! '
'Supported environment: "matrix".')
skip += 8
entry = mtd()
table = mtable(mtr(entry))
node.append(table)
node = entry
elif name == 'end':
if not string.startswith('{matrix}'):
raise SyntaxError(r'Expected "\end{matrix}"!')
skip += 8
node = node.close().close().close()
elif name in ('text', 'mathrm'):
if string[0] != '{':
raise SyntaxError(r'Expected "\text{...}"!')
i = string.find('}')
if i == -1:
raise SyntaxError(r'Expected "\text{...}"!')
node = node.append(mtext(string[1:i]))
skip += i + 1
elif name == 'sqrt':
sqrt = msqrt()
node.append(sqrt)
node = sqrt
elif name == 'frac':
frac = mfrac()
node.append(frac)
node = frac
elif name == 'left':
for par in ['(', '[', '|', '\\{', '\\langle', '.']:
if string.startswith(par):
break
else:
raise SyntaxError('Missing left-brace!')
fenced = mfenced(par)
node.append(fenced)
row = mrow()
fenced.append(row)
node = row
skip += len(par)
elif name == 'right':
for par in [')', ']', '|', '\\}', '\\rangle', '.']:
if string.startswith(par):
break
else:
raise SyntaxError('Missing right-brace!')
node = node.close()
node.closepar = par
node = node.close()
skip += len(par)
elif name == 'not':
for operator in negatables:
if string.startswith(operator):
break
else:
raise SyntaxError(r'Expected something to negate: "\not ..."!')
node = node.append(mo(negatables[operator]))
skip += len(operator)
elif name == 'mathbf':
style = mstyle(nchildren=1, fontweight='bold')
node.append(style)
node = style
elif name == 'mathbb':
if string[0] != '{' or not string[1].isupper() or string[2] != '}':
raise SyntaxError(r'Expected something like "\mathbb{A}"!')
node = node.append(mi(mathbb[string[1]]))
skip += 3
elif name in ('mathscr', 'mathcal'):
if string[0] != '{' or string[2] != '}':
raise SyntaxError(r'Expected something like "\mathscr{A}"!')
node = node.append(mi(mathscr[string[1]]))
skip += 3
elif name == 'colon': # "normal" colon, not binary operator
node = node.append(mo(':')) # TODO: add ``lspace="0pt"``
elif name in Greek: # Greek capitals (upright in "TeX style")
node = node.append(mo(Greek[name]))
# TODO: "ISO style" sets them italic. Could we use a class argument
# to enable styling via CSS?
elif name in letters:
node = node.append(mi(letters[name]))
elif name in special:
node = node.append(mo(special[name]))
elif name in functions:
node = node.append(mo(name))
elif name in over:
ovr = mover(mo(over[name]), reversed=True)
node.append(ovr)
node = ovr
else:
raise SyntaxError('Unknown LaTeX command: ' + name)
return node, skip
def tex2mathml(tex_math, inline=True):
"""Return string with MathML code corresponding to `tex_math`.
`inline`=True is for inline math and `inline`=False for displayed math.
"""
mathml_tree = parse_latex_math(tex_math, inline=inline)
return ''.join(mathml_tree.xml())

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,146 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# :Id: $Id: tex2mathml_extern.py 8208 2018-01-04 07:03:42Z milde $
# :Copyright: © 2015 Günter Milde.
# :License: Released under the terms of the `2-Clause BSD license`_, in short:
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.
# This file is offered as-is, without any warranty.
#
# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause
# Wrappers for TeX->MathML conversion by external tools
# =====================================================
import subprocess
document_template = r"""\documentclass{article}
\usepackage{amsmath}
\begin{document}
%s
\end{document}
"""
def latexml(math_code, reporter=None):
"""Convert LaTeX math code to MathML with LaTeXML_
.. _LaTeXML: http://dlmf.nist.gov/LaTeXML/
"""
p = subprocess.Popen(['latexml',
'-', # read from stdin
# '--preload=amsmath',
'--inputencoding=utf8',
],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True)
p.stdin.write((document_template % math_code).encode('utf8'))
p.stdin.close()
latexml_code = p.stdout.read()
latexml_err = p.stderr.read().decode('utf8')
if reporter and (latexml_err.find('Error') >= 0 or not latexml_code):
reporter.error(latexml_err)
post_p = subprocess.Popen(['latexmlpost',
'-',
'--nonumbersections',
'--format=xhtml',
# '--linelength=78', # experimental
'--'
],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True)
post_p.stdin.write(latexml_code)
post_p.stdin.close()
result = post_p.stdout.read().decode('utf8')
post_p_err = post_p.stderr.read().decode('utf8')
if reporter and (post_p_err.find('Error') >= 0 or not result):
reporter.error(post_p_err)
# extract MathML code:
start,end = result.find('<math'), result.find('</math>')+7
result = result[start:end]
if 'class="ltx_ERROR' in result:
raise SyntaxError(result)
return result
def ttm(math_code, reporter=None):
"""Convert LaTeX math code to MathML with TtM_
.. _TtM: http://hutchinson.belmont.ma.us/tth/mml/
"""
p = subprocess.Popen(['ttm',
# '-i', # italic font for equations. Default roman.
'-u', # unicode character encoding. (Default iso-8859-1).
'-r', # output raw MathML (no preamble or postlude)
],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True)
p.stdin.write((document_template % math_code).encode('utf8'))
p.stdin.close()
result = p.stdout.read()
err = p.stderr.read().decode('utf8')
if err.find('**** Unknown') >= 0:
msg = '\n'.join([line for line in err.splitlines()
if line.startswith('****')])
raise SyntaxError('\nMessage from external converter TtM:\n'+ msg)
if reporter and err.find('**** Error') >= 0 or not result:
reporter.error(err)
start,end = result.find('<math'), result.find('</math>')+7
result = result[start:end]
return result
def blahtexml(math_code, inline=True, reporter=None):
"""Convert LaTeX math code to MathML with blahtexml_
.. _blahtexml: http://gva.noekeon.org/blahtexml/
"""
options = ['--mathml',
'--indented',
'--spacing', 'moderate',
'--mathml-encoding', 'raw',
'--other-encoding', 'raw',
'--doctype-xhtml+mathml',
'--annotate-TeX',
]
if inline:
mathmode_arg = ''
else:
mathmode_arg = 'mode="display"'
options.append('--displaymath')
p = subprocess.Popen(['blahtexml']+options,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
close_fds=True)
p.stdin.write(math_code.encode('utf8'))
p.stdin.close()
result = p.stdout.read().decode('utf8')
err = p.stderr.read().decode('utf8')
if result.find('<error>') >= 0:
raise SyntaxError('\nMessage from external converter blahtexml:\n'
+result[result.find('<message>')+9:result.find('</message>')])
if reporter and (err.find('**** Error') >= 0 or not result):
reporter.error(err)
start,end = result.find('<markup>')+9, result.find('</markup>')
result = ('<math xmlns="http://www.w3.org/1998/Math/MathML"%s>\n'
'%s</math>\n') % (mathmode_arg, result[start:end])
return result
# self-test
if __name__ == "__main__":
example = r'\frac{\partial \sin^2(\alpha)}{\partial \vec r} \varpi \, \text{Grüße}'
# print latexml(example).encode('utf8')
# print ttm(example)#.encode('utf8')
print(blahtexml(example).encode('utf8'))

View File

@@ -0,0 +1,662 @@
# -*- coding: utf-8 -*-
# LaTeX math to Unicode symbols translation dictionaries.
# Generated with ``write_tex2unichar.py`` from the data in
# http://milde.users.sourceforge.net/LUCR/Math/
# Includes commands from: wasysym, stmaryrd, mathdots, mathabx, esint, bbold, amsxtra, amsmath, amssymb, standard LaTeX
mathaccent = {
'acute': '\u0301', # x́ COMBINING ACUTE ACCENT
'bar': '\u0304', # x̄ COMBINING MACRON
'breve': '\u0306', # x̆ COMBINING BREVE
'check': '\u030c', # x̌ COMBINING CARON
'ddddot': '\u20dc', # x⃜ COMBINING FOUR DOTS ABOVE
'dddot': '\u20db', # x⃛ COMBINING THREE DOTS ABOVE
'ddot': '\u0308', # ẍ COMBINING DIAERESIS
'dot': '\u0307', # ẋ COMBINING DOT ABOVE
'grave': '\u0300', # x̀ COMBINING GRAVE ACCENT
'hat': '\u0302', # x̂ COMBINING CIRCUMFLEX ACCENT
'mathring': '\u030a', # x̊ COMBINING RING ABOVE
'not': '\u0338', # x̸ COMBINING LONG SOLIDUS OVERLAY
'overleftarrow': '\u20d6', # x⃖ COMBINING LEFT ARROW ABOVE
'overleftrightarrow': '\u20e1', # x⃡ COMBINING LEFT RIGHT ARROW ABOVE
'overline': '\u0305', # x̅ COMBINING OVERLINE
'overrightarrow': '\u20d7', # x⃗ COMBINING RIGHT ARROW ABOVE
'tilde': '\u0303', # x̃ COMBINING TILDE
'underbar': '\u0331', # x̱ COMBINING MACRON BELOW
'underleftarrow': '\u20ee', # x⃮ COMBINING LEFT ARROW BELOW
'underline': '\u0332', # x̲ COMBINING LOW LINE
'underrightarrow': '\u20ef', # x⃯ COMBINING RIGHT ARROW BELOW
'vec': '\u20d7', # x⃗ COMBINING RIGHT ARROW ABOVE
'widehat': '\u0302', # x̂ COMBINING CIRCUMFLEX ACCENT
'widetilde': '\u0303', # x̃ COMBINING TILDE
}
mathalpha = {
'Bbbk': '\U0001d55c', # 𝕜 MATHEMATICAL DOUBLE-STRUCK SMALL K
'Delta': '\u0394', # Δ GREEK CAPITAL LETTER DELTA
'Gamma': '\u0393', # Γ GREEK CAPITAL LETTER GAMMA
'Im': '\u2111', # BLACK-LETTER CAPITAL I
'Lambda': '\u039b', # Λ GREEK CAPITAL LETTER LAMDA
'Omega': '\u03a9', # Ω GREEK CAPITAL LETTER OMEGA
'Phi': '\u03a6', # Φ GREEK CAPITAL LETTER PHI
'Pi': '\u03a0', # Π GREEK CAPITAL LETTER PI
'Psi': '\u03a8', # Ψ GREEK CAPITAL LETTER PSI
'Re': '\u211c', # BLACK-LETTER CAPITAL R
'Sigma': '\u03a3', # Σ GREEK CAPITAL LETTER SIGMA
'Theta': '\u0398', # Θ GREEK CAPITAL LETTER THETA
'Upsilon': '\u03a5', # Υ GREEK CAPITAL LETTER UPSILON
'Xi': '\u039e', # Ξ GREEK CAPITAL LETTER XI
'aleph': '\u2135', # ℵ ALEF SYMBOL
'alpha': '\u03b1', # α GREEK SMALL LETTER ALPHA
'beta': '\u03b2', # β GREEK SMALL LETTER BETA
'beth': '\u2136', # ℶ BET SYMBOL
'chi': '\u03c7', # χ GREEK SMALL LETTER CHI
'daleth': '\u2138', # ℸ DALET SYMBOL
'delta': '\u03b4', # δ GREEK SMALL LETTER DELTA
'digamma': '\u03dc', # Ϝ GREEK LETTER DIGAMMA
'ell': '\u2113', # SCRIPT SMALL L
'epsilon': '\u03f5', # ϵ GREEK LUNATE EPSILON SYMBOL
'eta': '\u03b7', # η GREEK SMALL LETTER ETA
'eth': '\xf0', # ð LATIN SMALL LETTER ETH
'gamma': '\u03b3', # γ GREEK SMALL LETTER GAMMA
'gimel': '\u2137', # ℷ GIMEL SYMBOL
'hbar': '\u210f', # ℏ PLANCK CONSTANT OVER TWO PI
'hslash': '\u210f', # ℏ PLANCK CONSTANT OVER TWO PI
'imath': '\u0131', # ı LATIN SMALL LETTER DOTLESS I
'iota': '\u03b9', # ι GREEK SMALL LETTER IOTA
'jmath': '\u0237', # ȷ LATIN SMALL LETTER DOTLESS J
'kappa': '\u03ba', # κ GREEK SMALL LETTER KAPPA
'lambda': '\u03bb', # λ GREEK SMALL LETTER LAMDA
'mu': '\u03bc', # μ GREEK SMALL LETTER MU
'nu': '\u03bd', # ν GREEK SMALL LETTER NU
'omega': '\u03c9', # ω GREEK SMALL LETTER OMEGA
'phi': '\u03d5', # ϕ GREEK PHI SYMBOL
'pi': '\u03c0', # π GREEK SMALL LETTER PI
'psi': '\u03c8', # ψ GREEK SMALL LETTER PSI
'rho': '\u03c1', # ρ GREEK SMALL LETTER RHO
'sigma': '\u03c3', # σ GREEK SMALL LETTER SIGMA
'tau': '\u03c4', # τ GREEK SMALL LETTER TAU
'theta': '\u03b8', # θ GREEK SMALL LETTER THETA
'upsilon': '\u03c5', # υ GREEK SMALL LETTER UPSILON
'varDelta': '\U0001d6e5', # 𝛥 MATHEMATICAL ITALIC CAPITAL DELTA
'varGamma': '\U0001d6e4', # 𝛤 MATHEMATICAL ITALIC CAPITAL GAMMA
'varLambda': '\U0001d6ec', # 𝛬 MATHEMATICAL ITALIC CAPITAL LAMDA
'varOmega': '\U0001d6fa', # 𝛺 MATHEMATICAL ITALIC CAPITAL OMEGA
'varPhi': '\U0001d6f7', # 𝛷 MATHEMATICAL ITALIC CAPITAL PHI
'varPi': '\U0001d6f1', # 𝛱 MATHEMATICAL ITALIC CAPITAL PI
'varPsi': '\U0001d6f9', # 𝛹 MATHEMATICAL ITALIC CAPITAL PSI
'varSigma': '\U0001d6f4', # 𝛴 MATHEMATICAL ITALIC CAPITAL SIGMA
'varTheta': '\U0001d6e9', # 𝛩 MATHEMATICAL ITALIC CAPITAL THETA
'varUpsilon': '\U0001d6f6', # 𝛶 MATHEMATICAL ITALIC CAPITAL UPSILON
'varXi': '\U0001d6ef', # 𝛯 MATHEMATICAL ITALIC CAPITAL XI
'varepsilon': '\u03b5', # ε GREEK SMALL LETTER EPSILON
'varkappa': '\U0001d718', # 𝜘 MATHEMATICAL ITALIC KAPPA SYMBOL
'varphi': '\u03c6', # φ GREEK SMALL LETTER PHI
'varpi': '\u03d6', # ϖ GREEK PI SYMBOL
'varrho': '\u03f1', # ϱ GREEK RHO SYMBOL
'varsigma': '\u03c2', # ς GREEK SMALL LETTER FINAL SIGMA
'vartheta': '\u03d1', # ϑ GREEK THETA SYMBOL
'wp': '\u2118', # ℘ SCRIPT CAPITAL P
'xi': '\u03be', # ξ GREEK SMALL LETTER XI
'zeta': '\u03b6', # ζ GREEK SMALL LETTER ZETA
}
mathbin = {
'Cap': '\u22d2', # ⋒ DOUBLE INTERSECTION
'Circle': '\u25cb', # ○ WHITE CIRCLE
'Cup': '\u22d3', # ⋓ DOUBLE UNION
'LHD': '\u25c0', # ◀ BLACK LEFT-POINTING TRIANGLE
'RHD': '\u25b6', # ▶ BLACK RIGHT-POINTING TRIANGLE
'amalg': '\u2a3f', # ⨿ AMALGAMATION OR COPRODUCT
'ast': '\u2217', # ASTERISK OPERATOR
'barwedge': '\u22bc', # ⊼ NAND
'bigtriangledown': '\u25bd', # ▽ WHITE DOWN-POINTING TRIANGLE
'bigtriangleup': '\u25b3', # △ WHITE UP-POINTING TRIANGLE
'bindnasrepma': '\u214b', # ⅋ TURNED AMPERSAND
'blacklozenge': '\u29eb', # ⧫ BLACK LOZENGE
'blacktriangledown': '\u25be', # ▾ BLACK DOWN-POINTING SMALL TRIANGLE
'blacktriangleleft': '\u25c2', # ◂ BLACK LEFT-POINTING SMALL TRIANGLE
'blacktriangleright': '\u25b8', # ▸ BLACK RIGHT-POINTING SMALL TRIANGLE
'blacktriangleup': '\u25b4', # ▴ BLACK UP-POINTING SMALL TRIANGLE
'boxast': '\u29c6', # ⧆ SQUARED ASTERISK
'boxbar': '\u25eb', # ◫ WHITE SQUARE WITH VERTICAL BISECTING LINE
'boxbox': '\u29c8', # ⧈ SQUARED SQUARE
'boxbslash': '\u29c5', # ⧅ SQUARED FALLING DIAGONAL SLASH
'boxcircle': '\u29c7', # ⧇ SQUARED SMALL CIRCLE
'boxdot': '\u22a1', # ⊡ SQUARED DOT OPERATOR
'boxminus': '\u229f', # ⊟ SQUARED MINUS
'boxplus': '\u229e', # ⊞ SQUARED PLUS
'boxslash': '\u29c4', # ⧄ SQUARED RISING DIAGONAL SLASH
'boxtimes': '\u22a0', # ⊠ SQUARED TIMES
'bullet': '\u2219', # ∙ BULLET OPERATOR
'cap': '\u2229', # ∩ INTERSECTION
'cdot': '\u22c5', # ⋅ DOT OPERATOR
'circ': '\u2218', # ∘ RING OPERATOR
'circledast': '\u229b', # ⊛ CIRCLED ASTERISK OPERATOR
'circledcirc': '\u229a', # ⊚ CIRCLED RING OPERATOR
'circleddash': '\u229d', # ⊝ CIRCLED DASH
'cup': '\u222a', # UNION
'curlyvee': '\u22ce', # ⋎ CURLY LOGICAL OR
'curlywedge': '\u22cf', # ⋏ CURLY LOGICAL AND
'dagger': '\u2020', # † DAGGER
'ddagger': '\u2021', # ‡ DOUBLE DAGGER
'diamond': '\u22c4', # ⋄ DIAMOND OPERATOR
'div': '\xf7', # ÷ DIVISION SIGN
'divideontimes': '\u22c7', # ⋇ DIVISION TIMES
'dotplus': '\u2214', # ∔ DOT PLUS
'doublebarwedge': '\u2a5e', # ⩞ LOGICAL AND WITH DOUBLE OVERBAR
'intercal': '\u22ba', # ⊺ INTERCALATE
'interleave': '\u2af4', # ⫴ TRIPLE VERTICAL BAR BINARY RELATION
'land': '\u2227', # ∧ LOGICAL AND
'leftthreetimes': '\u22cb', # ⋋ LEFT SEMIDIRECT PRODUCT
'lhd': '\u25c1', # ◁ WHITE LEFT-POINTING TRIANGLE
'lor': '\u2228', # LOGICAL OR
'ltimes': '\u22c9', # ⋉ LEFT NORMAL FACTOR SEMIDIRECT PRODUCT
'mp': '\u2213', # ∓ MINUS-OR-PLUS SIGN
'odot': '\u2299', # ⊙ CIRCLED DOT OPERATOR
'ominus': '\u2296', # ⊖ CIRCLED MINUS
'oplus': '\u2295', # ⊕ CIRCLED PLUS
'oslash': '\u2298', # ⊘ CIRCLED DIVISION SLASH
'otimes': '\u2297', # ⊗ CIRCLED TIMES
'pm': '\xb1', # ± PLUS-MINUS SIGN
'rhd': '\u25b7', # ▷ WHITE RIGHT-POINTING TRIANGLE
'rightthreetimes': '\u22cc', # ⋌ RIGHT SEMIDIRECT PRODUCT
'rtimes': '\u22ca', # ⋊ RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT
'setminus': '\u29f5', # REVERSE SOLIDUS OPERATOR
'slash': '\u2215', # DIVISION SLASH
'smallsetminus': '\u2216', # SET MINUS
'smalltriangledown': '\u25bf', # ▿ WHITE DOWN-POINTING SMALL TRIANGLE
'smalltriangleleft': '\u25c3', # ◃ WHITE LEFT-POINTING SMALL TRIANGLE
'smalltriangleright': '\u25b9', # ▹ WHITE RIGHT-POINTING SMALL TRIANGLE
'smalltriangleup': '\u25b5', # ▵ WHITE UP-POINTING SMALL TRIANGLE
'sqcap': '\u2293', # ⊓ SQUARE CAP
'sqcup': '\u2294', # ⊔ SQUARE CUP
'sslash': '\u2afd', # ⫽ DOUBLE SOLIDUS OPERATOR
'star': '\u22c6', # ⋆ STAR OPERATOR
'talloblong': '\u2afe', # ⫾ WHITE VERTICAL BAR
'times': '\xd7', # × MULTIPLICATION SIGN
'triangle': '\u25b3', # △ WHITE UP-POINTING TRIANGLE
'triangledown': '\u25bf', # ▿ WHITE DOWN-POINTING SMALL TRIANGLE
'triangleleft': '\u25c3', # ◃ WHITE LEFT-POINTING SMALL TRIANGLE
'triangleright': '\u25b9', # ▹ WHITE RIGHT-POINTING SMALL TRIANGLE
'uplus': '\u228e', # ⊎ MULTISET UNION
'vartriangle': '\u25b3', # △ WHITE UP-POINTING TRIANGLE
'vee': '\u2228', # LOGICAL OR
'veebar': '\u22bb', # ⊻ XOR
'wedge': '\u2227', # ∧ LOGICAL AND
'wr': '\u2240', # ≀ WREATH PRODUCT
}
mathclose = {
'Rbag': '\u27c6', # ⟆ RIGHT S-SHAPED BAG DELIMITER
'lrcorner': '\u231f', # ⌟ BOTTOM RIGHT CORNER
'rangle': '\u27e9', # ⟩ MATHEMATICAL RIGHT ANGLE BRACKET
'rbag': '\u27c6', # ⟆ RIGHT S-SHAPED BAG DELIMITER
'rbrace': '}', # } RIGHT CURLY BRACKET
'rbrack': ']', # ] RIGHT SQUARE BRACKET
'rceil': '\u2309', # ⌉ RIGHT CEILING
'rfloor': '\u230b', # ⌋ RIGHT FLOOR
'rgroup': '\u27ef', # ⟯ MATHEMATICAL RIGHT FLATTENED PARENTHESIS
'rrbracket': '\u27e7', # ⟧ MATHEMATICAL RIGHT WHITE SQUARE BRACKET
'rrparenthesis': '\u2988', # ⦈ Z NOTATION RIGHT IMAGE BRACKET
'urcorner': '\u231d', # ⌝ TOP RIGHT CORNER
'}': '}', # } RIGHT CURLY BRACKET
}
mathfence = {
'Vert': '\u2016', # ‖ DOUBLE VERTICAL LINE
'vert': '|', # | VERTICAL LINE
'|': '\u2016', # ‖ DOUBLE VERTICAL LINE
}
mathop = {
'Join': '\u2a1d', # ⨝ JOIN
'bigcap': '\u22c2', # ⋂ N-ARY INTERSECTION
'bigcup': '\u22c3', # N-ARY UNION
'biginterleave': '\u2afc', # ⫼ LARGE TRIPLE VERTICAL BAR OPERATOR
'bigodot': '\u2a00', # ⨀ N-ARY CIRCLED DOT OPERATOR
'bigoplus': '\u2a01', # ⨁ N-ARY CIRCLED PLUS OPERATOR
'bigotimes': '\u2a02', # ⨂ N-ARY CIRCLED TIMES OPERATOR
'bigsqcup': '\u2a06', # ⨆ N-ARY SQUARE UNION OPERATOR
'biguplus': '\u2a04', # ⨄ N-ARY UNION OPERATOR WITH PLUS
'bigvee': '\u22c1', # N-ARY LOGICAL OR
'bigwedge': '\u22c0', # ⋀ N-ARY LOGICAL AND
'coprod': '\u2210', # ∐ N-ARY COPRODUCT
'fatsemi': '\u2a1f', # ⨟ Z NOTATION SCHEMA COMPOSITION
'fint': '\u2a0f', # ⨏ INTEGRAL AVERAGE WITH SLASH
'iiiint': '\u2a0c', # ⨌ QUADRUPLE INTEGRAL OPERATOR
'iiint': '\u222d', # ∭ TRIPLE INTEGRAL
'iint': '\u222c', # ∬ DOUBLE INTEGRAL
'int': '\u222b', # ∫ INTEGRAL
'oiint': '\u222f', # ∯ SURFACE INTEGRAL
'oint': '\u222e', # ∮ CONTOUR INTEGRAL
'ointctrclockwise': '\u2233', # ∳ ANTICLOCKWISE CONTOUR INTEGRAL
'prod': '\u220f', # ∏ N-ARY PRODUCT
'sqint': '\u2a16', # ⨖ QUATERNION INTEGRAL OPERATOR
'sum': '\u2211', # ∑ N-ARY SUMMATION
'varointclockwise': '\u2232', # ∲ CLOCKWISE CONTOUR INTEGRAL
}
mathopen = {
'Lbag': '\u27c5', # ⟅ LEFT S-SHAPED BAG DELIMITER
'langle': '\u27e8', # ⟨ MATHEMATICAL LEFT ANGLE BRACKET
'lbag': '\u27c5', # ⟅ LEFT S-SHAPED BAG DELIMITER
'lbrace': '{', # { LEFT CURLY BRACKET
'lbrack': '[', # [ LEFT SQUARE BRACKET
'lceil': '\u2308', # ⌈ LEFT CEILING
'lfloor': '\u230a', # ⌊ LEFT FLOOR
'lgroup': '\u27ee', # ⟮ MATHEMATICAL LEFT FLATTENED PARENTHESIS
'llbracket': '\u27e6', # ⟦ MATHEMATICAL LEFT WHITE SQUARE BRACKET
'llcorner': '\u231e', # ⌞ BOTTOM LEFT CORNER
'llparenthesis': '\u2987', # ⦇ Z NOTATION LEFT IMAGE BRACKET
'ulcorner': '\u231c', # ⌜ TOP LEFT CORNER
'{': '{', # { LEFT CURLY BRACKET
}
mathord = {
'#': '#', # # NUMBER SIGN
'$': '$', # $ DOLLAR SIGN
'%': '%', # % PERCENT SIGN
'&': '&', # & AMPERSAND
'AC': '\u223f', # ∿ SINE WAVE
'APLcomment': '\u235d', # ⍝ APL FUNCTIONAL SYMBOL UP SHOE JOT
'APLdownarrowbox': '\u2357', # ⍗ APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW
'APLinput': '\u235e', # ⍞ APL FUNCTIONAL SYMBOL QUOTE QUAD
'APLinv': '\u2339', # ⌹ APL FUNCTIONAL SYMBOL QUAD DIVIDE
'APLleftarrowbox': '\u2347', # ⍇ APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW
'APLlog': '\u235f', # ⍟ APL FUNCTIONAL SYMBOL CIRCLE STAR
'APLrightarrowbox': '\u2348', # ⍈ APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW
'APLuparrowbox': '\u2350', # ⍐ APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW
'Aries': '\u2648', # ♈ ARIES
'CIRCLE': '\u25cf', # ● BLACK CIRCLE
'CheckedBox': '\u2611', # ☑ BALLOT BOX WITH CHECK
'Diamond': '\u25c7', # ◇ WHITE DIAMOND
'Finv': '\u2132', # Ⅎ TURNED CAPITAL F
'Game': '\u2141', # ⅁ TURNED SANS-SERIF CAPITAL G
'Gemini': '\u264a', # ♊ GEMINI
'Jupiter': '\u2643', # ♃ JUPITER
'LEFTCIRCLE': '\u25d6', # ◖ LEFT HALF BLACK CIRCLE
'LEFTcircle': '\u25d0', # ◐ CIRCLE WITH LEFT HALF BLACK
'Leo': '\u264c', # ♌ LEO
'Libra': '\u264e', # ♎ LIBRA
'Mars': '\u2642', # ♂ MALE SIGN
'Mercury': '\u263f', # ☿ MERCURY
'Neptune': '\u2646', # ♆ NEPTUNE
'Pluto': '\u2647', # ♇ PLUTO
'RIGHTCIRCLE': '\u25d7', # ◗ RIGHT HALF BLACK CIRCLE
'RIGHTcircle': '\u25d1', # ◑ CIRCLE WITH RIGHT HALF BLACK
'Saturn': '\u2644', # ♄ SATURN
'Scorpio': '\u264f', # ♏ SCORPIUS
'Square': '\u2610', # ☐ BALLOT BOX
'Sun': '\u2609', # ☉ SUN
'Taurus': '\u2649', # ♉ TAURUS
'Uranus': '\u2645', # ♅ URANUS
'Venus': '\u2640', # ♀ FEMALE SIGN
'XBox': '\u2612', # ☒ BALLOT BOX WITH X
'Yup': '\u2144', # ⅄ TURNED SANS-SERIF CAPITAL Y
'_': '_', # _ LOW LINE
'angle': '\u2220', # ∠ ANGLE
'aquarius': '\u2652', # ♒ AQUARIUS
'aries': '\u2648', # ♈ ARIES
'ast': '*', # * ASTERISK
'backepsilon': '\u03f6', # ϶ GREEK REVERSED LUNATE EPSILON SYMBOL
'backprime': '\u2035', # REVERSED PRIME
'backslash': '\\', # \ REVERSE SOLIDUS
'because': '\u2235', # ∵ BECAUSE
'bigstar': '\u2605', # ★ BLACK STAR
'binampersand': '&', # & AMPERSAND
'blacklozenge': '\u2b27', # ⬧ BLACK MEDIUM LOZENGE
'blacksmiley': '\u263b', # ☻ BLACK SMILING FACE
'blacksquare': '\u25fc', # ◼ BLACK MEDIUM SQUARE
'bot': '\u22a5', # ⊥ UP TACK
'boy': '\u2642', # ♂ MALE SIGN
'cancer': '\u264b', # ♋ CANCER
'capricornus': '\u2651', # ♑ CAPRICORN
'cdots': '\u22ef', # ⋯ MIDLINE HORIZONTAL ELLIPSIS
'cent': '\xa2', # ¢ CENT SIGN
'centerdot': '\u2b1d', # ⬝ BLACK VERY SMALL SQUARE
'checkmark': '\u2713', # ✓ CHECK MARK
'circlearrowleft': '\u21ba', # ↺ ANTICLOCKWISE OPEN CIRCLE ARROW
'circlearrowright': '\u21bb', # ↻ CLOCKWISE OPEN CIRCLE ARROW
'circledR': '\xae', # ® REGISTERED SIGN
'circledcirc': '\u25ce', # ◎ BULLSEYE
'clubsuit': '\u2663', # ♣ BLACK CLUB SUIT
'complement': '\u2201', # ∁ COMPLEMENT
'dasharrow': '\u21e2', # ⇢ RIGHTWARDS DASHED ARROW
'dashleftarrow': '\u21e0', # ⇠ LEFTWARDS DASHED ARROW
'dashrightarrow': '\u21e2', # ⇢ RIGHTWARDS DASHED ARROW
'diameter': '\u2300', # ⌀ DIAMETER SIGN
'diamondsuit': '\u2662', # ♢ WHITE DIAMOND SUIT
'earth': '\u2641', # ♁ EARTH
'exists': '\u2203', # ∃ THERE EXISTS
'female': '\u2640', # ♀ FEMALE SIGN
'flat': '\u266d', # ♭ MUSIC FLAT SIGN
'forall': '\u2200', # ∀ FOR ALL
'fourth': '\u2057', # ⁗ QUADRUPLE PRIME
'frownie': '\u2639', # ☹ WHITE FROWNING FACE
'gemini': '\u264a', # ♊ GEMINI
'girl': '\u2640', # ♀ FEMALE SIGN
'heartsuit': '\u2661', # ♡ WHITE HEART SUIT
'infty': '\u221e', # ∞ INFINITY
'invneg': '\u2310', # ⌐ REVERSED NOT SIGN
'jupiter': '\u2643', # ♃ JUPITER
'ldots': '\u2026', # … HORIZONTAL ELLIPSIS
'leftmoon': '\u263e', # ☾ LAST QUARTER MOON
'leftturn': '\u21ba', # ↺ ANTICLOCKWISE OPEN CIRCLE ARROW
'leo': '\u264c', # ♌ LEO
'libra': '\u264e', # ♎ LIBRA
'lnot': '\xac', # ¬ NOT SIGN
'lozenge': '\u25ca', # ◊ LOZENGE
'male': '\u2642', # ♂ MALE SIGN
'maltese': '\u2720', # ✠ MALTESE CROSS
'mathdollar': '$', # $ DOLLAR SIGN
'measuredangle': '\u2221', # ∡ MEASURED ANGLE
'mercury': '\u263f', # ☿ MERCURY
'mho': '\u2127', # ℧ INVERTED OHM SIGN
'nabla': '\u2207', # ∇ NABLA
'natural': '\u266e', # ♮ MUSIC NATURAL SIGN
'neg': '\xac', # ¬ NOT SIGN
'neptune': '\u2646', # ♆ NEPTUNE
'nexists': '\u2204', # ∄ THERE DOES NOT EXIST
'notbackslash': '\u2340', # ⍀ APL FUNCTIONAL SYMBOL BACKSLASH BAR
'partial': '\u2202', # ∂ PARTIAL DIFFERENTIAL
'pisces': '\u2653', # ♓ PISCES
'pluto': '\u2647', # ♇ PLUTO
'pounds': '\xa3', # £ POUND SIGN
'prime': '\u2032', # PRIME
'quarternote': '\u2669', # ♩ QUARTER NOTE
'rightmoon': '\u263d', # ☽ FIRST QUARTER MOON
'rightturn': '\u21bb', # ↻ CLOCKWISE OPEN CIRCLE ARROW
'sagittarius': '\u2650', # ♐ SAGITTARIUS
'saturn': '\u2644', # ♄ SATURN
'scorpio': '\u264f', # ♏ SCORPIUS
'second': '\u2033', # ″ DOUBLE PRIME
'sharp': '\u266f', # ♯ MUSIC SHARP SIGN
'sim': '~', # ~ TILDE
'slash': '/', # / SOLIDUS
'smiley': '\u263a', # ☺ WHITE SMILING FACE
'spadesuit': '\u2660', # ♠ BLACK SPADE SUIT
'spddot': '\xa8', # ¨ DIAERESIS
'sphat': '^', # ^ CIRCUMFLEX ACCENT
'sphericalangle': '\u2222', # ∢ SPHERICAL ANGLE
'sptilde': '~', # ~ TILDE
'square': '\u25fb', # ◻ WHITE MEDIUM SQUARE
'sun': '\u263c', # ☼ WHITE SUN WITH RAYS
'taurus': '\u2649', # ♉ TAURUS
'therefore': '\u2234', # ∴ THEREFORE
'third': '\u2034', # ‴ TRIPLE PRIME
'top': '\u22a4', # DOWN TACK
'triangleleft': '\u25c5', # ◅ WHITE LEFT-POINTING POINTER
'triangleright': '\u25bb', # ▻ WHITE RIGHT-POINTING POINTER
'twonotes': '\u266b', # ♫ BEAMED EIGHTH NOTES
'uranus': '\u2645', # ♅ URANUS
'varEarth': '\u2641', # ♁ EARTH
'varnothing': '\u2205', # ∅ EMPTY SET
'virgo': '\u264d', # ♍ VIRGO
'wasylozenge': '\u2311', # ⌑ SQUARE LOZENGE
'wasytherefore': '\u2234', # ∴ THEREFORE
'yen': '\xa5', # ¥ YEN SIGN
}
mathover = {
'overbrace': '\u23de', # ⏞ TOP CURLY BRACKET
'wideparen': '\u23dc', # ⏜ TOP PARENTHESIS
}
mathradical = {
'sqrt': '\u221a', # √ SQUARE ROOT
'sqrt[3]': '\u221b', # ∛ CUBE ROOT
'sqrt[4]': '\u221c', # ∜ FOURTH ROOT
}
mathrel = {
'Bumpeq': '\u224e', # ≎ GEOMETRICALLY EQUIVALENT TO
'Doteq': '\u2251', # ≑ GEOMETRICALLY EQUAL TO
'Downarrow': '\u21d3', # ⇓ DOWNWARDS DOUBLE ARROW
'Leftarrow': '\u21d0', # ⇐ LEFTWARDS DOUBLE ARROW
'Leftrightarrow': '\u21d4', # ⇔ LEFT RIGHT DOUBLE ARROW
'Lleftarrow': '\u21da', # ⇚ LEFTWARDS TRIPLE ARROW
'Longleftarrow': '\u27f8', # ⟸ LONG LEFTWARDS DOUBLE ARROW
'Longleftrightarrow': '\u27fa', # ⟺ LONG LEFT RIGHT DOUBLE ARROW
'Longmapsfrom': '\u27fd', # ⟽ LONG LEFTWARDS DOUBLE ARROW FROM BAR
'Longmapsto': '\u27fe', # ⟾ LONG RIGHTWARDS DOUBLE ARROW FROM BAR
'Longrightarrow': '\u27f9', # ⟹ LONG RIGHTWARDS DOUBLE ARROW
'Lsh': '\u21b0', # ↰ UPWARDS ARROW WITH TIP LEFTWARDS
'Mapsfrom': '\u2906', # ⤆ LEFTWARDS DOUBLE ARROW FROM BAR
'Mapsto': '\u2907', # ⤇ RIGHTWARDS DOUBLE ARROW FROM BAR
'Rightarrow': '\u21d2', # ⇒ RIGHTWARDS DOUBLE ARROW
'Rrightarrow': '\u21db', # ⇛ RIGHTWARDS TRIPLE ARROW
'Rsh': '\u21b1', # ↱ UPWARDS ARROW WITH TIP RIGHTWARDS
'Subset': '\u22d0', # ⋐ DOUBLE SUBSET
'Supset': '\u22d1', # ⋑ DOUBLE SUPERSET
'Uparrow': '\u21d1', # ⇑ UPWARDS DOUBLE ARROW
'Updownarrow': '\u21d5', # ⇕ UP DOWN DOUBLE ARROW
'VDash': '\u22ab', # ⊫ DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
'Vdash': '\u22a9', # ⊩ FORCES
'Vvdash': '\u22aa', # ⊪ TRIPLE VERTICAL BAR RIGHT TURNSTILE
'apprge': '\u2273', # ≳ GREATER-THAN OR EQUIVALENT TO
'apprle': '\u2272', # ≲ LESS-THAN OR EQUIVALENT TO
'approx': '\u2248', # ≈ ALMOST EQUAL TO
'approxeq': '\u224a', # ≊ ALMOST EQUAL OR EQUAL TO
'asymp': '\u224d', # ≍ EQUIVALENT TO
'backsim': '\u223d', # ∽ REVERSED TILDE
'backsimeq': '\u22cd', # ⋍ REVERSED TILDE EQUALS
'barin': '\u22f6', # ⋶ ELEMENT OF WITH OVERBAR
'barleftharpoon': '\u296b', # ⥫ LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH
'barrightharpoon': '\u296d', # ⥭ RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH
'between': '\u226c', # ≬ BETWEEN
'bowtie': '\u22c8', # ⋈ BOWTIE
'bumpeq': '\u224f', # ≏ DIFFERENCE BETWEEN
'circeq': '\u2257', # ≗ RING EQUAL TO
'coloneq': '\u2254', # ≔ COLON EQUALS
'cong': '\u2245', # ≅ APPROXIMATELY EQUAL TO
'corresponds': '\u2259', # ≙ ESTIMATES
'curlyeqprec': '\u22de', # ⋞ EQUAL TO OR PRECEDES
'curlyeqsucc': '\u22df', # ⋟ EQUAL TO OR SUCCEEDS
'curvearrowleft': '\u21b6', # ↶ ANTICLOCKWISE TOP SEMICIRCLE ARROW
'curvearrowright': '\u21b7', # ↷ CLOCKWISE TOP SEMICIRCLE ARROW
'dashv': '\u22a3', # ⊣ LEFT TACK
'ddots': '\u22f1', # ⋱ DOWN RIGHT DIAGONAL ELLIPSIS
'dlsh': '\u21b2', # ↲ DOWNWARDS ARROW WITH TIP LEFTWARDS
'doteq': '\u2250', # ≐ APPROACHES THE LIMIT
'doteqdot': '\u2251', # ≑ GEOMETRICALLY EQUAL TO
'downarrow': '\u2193', # ↓ DOWNWARDS ARROW
'downdownarrows': '\u21ca', # ⇊ DOWNWARDS PAIRED ARROWS
'downdownharpoons': '\u2965', # ⥥ DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
'downharpoonleft': '\u21c3', # ⇃ DOWNWARDS HARPOON WITH BARB LEFTWARDS
'downharpoonright': '\u21c2', # ⇂ DOWNWARDS HARPOON WITH BARB RIGHTWARDS
'downuparrows': '\u21f5', # ⇵ DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW
'downupharpoons': '\u296f', # ⥯ DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
'drsh': '\u21b3', # ↳ DOWNWARDS ARROW WITH TIP RIGHTWARDS
'eqcirc': '\u2256', # ≖ RING IN EQUAL TO
'eqcolon': '\u2255', # ≕ EQUALS COLON
'eqsim': '\u2242', # ≂ MINUS TILDE
'eqslantgtr': '\u2a96', # ⪖ SLANTED EQUAL TO OR GREATER-THAN
'eqslantless': '\u2a95', # ⪕ SLANTED EQUAL TO OR LESS-THAN
'equiv': '\u2261', # ≡ IDENTICAL TO
'fallingdotseq': '\u2252', # ≒ APPROXIMATELY EQUAL TO OR THE IMAGE OF
'frown': '\u2322', # ⌢ FROWN
'ge': '\u2265', # ≥ GREATER-THAN OR EQUAL TO
'geq': '\u2265', # ≥ GREATER-THAN OR EQUAL TO
'geqq': '\u2267', # ≧ GREATER-THAN OVER EQUAL TO
'geqslant': '\u2a7e', # ⩾ GREATER-THAN OR SLANTED EQUAL TO
'gets': '\u2190', # ← LEFTWARDS ARROW
'gg': '\u226b', # ≫ MUCH GREATER-THAN
'ggcurly': '\u2abc', # ⪼ DOUBLE SUCCEEDS
'ggg': '\u22d9', # ⋙ VERY MUCH GREATER-THAN
'gnapprox': '\u2a8a', # ⪊ GREATER-THAN AND NOT APPROXIMATE
'gneq': '\u2a88', # ⪈ GREATER-THAN AND SINGLE-LINE NOT EQUAL TO
'gneqq': '\u2269', # ≩ GREATER-THAN BUT NOT EQUAL TO
'gnsim': '\u22e7', # ⋧ GREATER-THAN BUT NOT EQUIVALENT TO
'gtrapprox': '\u2a86', # ⪆ GREATER-THAN OR APPROXIMATE
'gtrdot': '\u22d7', # ⋗ GREATER-THAN WITH DOT
'gtreqless': '\u22db', # ⋛ GREATER-THAN EQUAL TO OR LESS-THAN
'gtreqqless': '\u2a8c', # ⪌ GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
'gtrless': '\u2277', # ≷ GREATER-THAN OR LESS-THAN
'gtrsim': '\u2273', # ≳ GREATER-THAN OR EQUIVALENT TO
'hash': '\u22d5', # ⋕ EQUAL AND PARALLEL TO
'hookleftarrow': '\u21a9', # ↩ LEFTWARDS ARROW WITH HOOK
'hookrightarrow': '\u21aa', # ↪ RIGHTWARDS ARROW WITH HOOK
'iddots': '\u22f0', # ⋰ UP RIGHT DIAGONAL ELLIPSIS
'impliedby': '\u27f8', # ⟸ LONG LEFTWARDS DOUBLE ARROW
'implies': '\u27f9', # ⟹ LONG RIGHTWARDS DOUBLE ARROW
'in': '\u2208', # ∈ ELEMENT OF
'le': '\u2264', # ≤ LESS-THAN OR EQUAL TO
'leftarrow': '\u2190', # ← LEFTWARDS ARROW
'leftarrowtail': '\u21a2', # ↢ LEFTWARDS ARROW WITH TAIL
'leftarrowtriangle': '\u21fd', # ⇽ LEFTWARDS OPEN-HEADED ARROW
'leftbarharpoon': '\u296a', # ⥪ LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH
'leftharpoondown': '\u21bd', # ↽ LEFTWARDS HARPOON WITH BARB DOWNWARDS
'leftharpoonup': '\u21bc', # ↼ LEFTWARDS HARPOON WITH BARB UPWARDS
'leftleftarrows': '\u21c7', # ⇇ LEFTWARDS PAIRED ARROWS
'leftleftharpoons': '\u2962', # ⥢ LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN
'leftrightarrow': '\u2194', # ↔ LEFT RIGHT ARROW
'leftrightarrows': '\u21c6', # ⇆ LEFTWARDS ARROW OVER RIGHTWARDS ARROW
'leftrightarrowtriangle': '\u21ff', # ⇿ LEFT RIGHT OPEN-HEADED ARROW
'leftrightharpoon': '\u294a', # ⥊ LEFT BARB UP RIGHT BARB DOWN HARPOON
'leftrightharpoons': '\u21cb', # ⇋ LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
'leftrightsquigarrow': '\u21ad', # ↭ LEFT RIGHT WAVE ARROW
'leftslice': '\u2aa6', # ⪦ LESS-THAN CLOSED BY CURVE
'leftsquigarrow': '\u21dc', # ⇜ LEFTWARDS SQUIGGLE ARROW
'leq': '\u2264', # ≤ LESS-THAN OR EQUAL TO
'leqq': '\u2266', # ≦ LESS-THAN OVER EQUAL TO
'leqslant': '\u2a7d', # ⩽ LESS-THAN OR SLANTED EQUAL TO
'lessapprox': '\u2a85', # ⪅ LESS-THAN OR APPROXIMATE
'lessdot': '\u22d6', # ⋖ LESS-THAN WITH DOT
'lesseqgtr': '\u22da', # ⋚ LESS-THAN EQUAL TO OR GREATER-THAN
'lesseqqgtr': '\u2a8b', # ⪋ LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN
'lessgtr': '\u2276', # ≶ LESS-THAN OR GREATER-THAN
'lesssim': '\u2272', # ≲ LESS-THAN OR EQUIVALENT TO
'lightning': '\u21af', # ↯ DOWNWARDS ZIGZAG ARROW
'll': '\u226a', # ≪ MUCH LESS-THAN
'llcurly': '\u2abb', # ⪻ DOUBLE PRECEDES
'lll': '\u22d8', # ⋘ VERY MUCH LESS-THAN
'lnapprox': '\u2a89', # ⪉ LESS-THAN AND NOT APPROXIMATE
'lneq': '\u2a87', # ⪇ LESS-THAN AND SINGLE-LINE NOT EQUAL TO
'lneqq': '\u2268', # ≨ LESS-THAN BUT NOT EQUAL TO
'lnsim': '\u22e6', # ⋦ LESS-THAN BUT NOT EQUIVALENT TO
'longleftarrow': '\u27f5', # ⟵ LONG LEFTWARDS ARROW
'longleftrightarrow': '\u27f7', # ⟷ LONG LEFT RIGHT ARROW
'longmapsfrom': '\u27fb', # ⟻ LONG LEFTWARDS ARROW FROM BAR
'longmapsto': '\u27fc', # ⟼ LONG RIGHTWARDS ARROW FROM BAR
'longrightarrow': '\u27f6', # ⟶ LONG RIGHTWARDS ARROW
'looparrowleft': '\u21ab', # ↫ LEFTWARDS ARROW WITH LOOP
'looparrowright': '\u21ac', # ↬ RIGHTWARDS ARROW WITH LOOP
'mapsfrom': '\u21a4', # ↤ LEFTWARDS ARROW FROM BAR
'mapsto': '\u21a6', # ↦ RIGHTWARDS ARROW FROM BAR
'mid': '\u2223', # DIVIDES
'models': '\u22a7', # ⊧ MODELS
'multimap': '\u22b8', # ⊸ MULTIMAP
'nLeftarrow': '\u21cd', # ⇍ LEFTWARDS DOUBLE ARROW WITH STROKE
'nLeftrightarrow': '\u21ce', # ⇎ LEFT RIGHT DOUBLE ARROW WITH STROKE
'nRightarrow': '\u21cf', # ⇏ RIGHTWARDS DOUBLE ARROW WITH STROKE
'nVDash': '\u22af', # ⊯ NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
'nVdash': '\u22ae', # ⊮ DOES NOT FORCE
'ncong': '\u2247', # ≇ NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
'ne': '\u2260', # ≠ NOT EQUAL TO
'nearrow': '\u2197', # ↗ NORTH EAST ARROW
'neq': '\u2260', # ≠ NOT EQUAL TO
'ngeq': '\u2271', # ≱ NEITHER GREATER-THAN NOR EQUAL TO
'ngtr': '\u226f', # ≯ NOT GREATER-THAN
'ni': '\u220b', # ∋ CONTAINS AS MEMBER
'nleftarrow': '\u219a', # ↚ LEFTWARDS ARROW WITH STROKE
'nleftrightarrow': '\u21ae', # ↮ LEFT RIGHT ARROW WITH STROKE
'nleq': '\u2270', # ≰ NEITHER LESS-THAN NOR EQUAL TO
'nless': '\u226e', # ≮ NOT LESS-THAN
'nmid': '\u2224', # ∤ DOES NOT DIVIDE
'notasymp': '\u226d', # ≭ NOT EQUIVALENT TO
'notin': '\u2209', # ∉ NOT AN ELEMENT OF
'notowner': '\u220c', # ∌ DOES NOT CONTAIN AS MEMBER
'notslash': '\u233f', # ⌿ APL FUNCTIONAL SYMBOL SLASH BAR
'nparallel': '\u2226', # ∦ NOT PARALLEL TO
'nprec': '\u2280', # ⊀ DOES NOT PRECEDE
'npreceq': '\u22e0', # ⋠ DOES NOT PRECEDE OR EQUAL
'nrightarrow': '\u219b', # ↛ RIGHTWARDS ARROW WITH STROKE
'nsim': '\u2241', # ≁ NOT TILDE
'nsubseteq': '\u2288', # ⊈ NEITHER A SUBSET OF NOR EQUAL TO
'nsucc': '\u2281', # ⊁ DOES NOT SUCCEED
'nsucceq': '\u22e1', # ⋡ DOES NOT SUCCEED OR EQUAL
'nsupseteq': '\u2289', # ⊉ NEITHER A SUPERSET OF NOR EQUAL TO
'ntriangleleft': '\u22ea', # ⋪ NOT NORMAL SUBGROUP OF
'ntrianglelefteq': '\u22ec', # ⋬ NOT NORMAL SUBGROUP OF OR EQUAL TO
'ntriangleright': '\u22eb', # ⋫ DOES NOT CONTAIN AS NORMAL SUBGROUP
'ntrianglerighteq': '\u22ed', # ⋭ DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
'nvDash': '\u22ad', # ⊭ NOT TRUE
'nvdash': '\u22ac', # ⊬ DOES NOT PROVE
'nwarrow': '\u2196', # ↖ NORTH WEST ARROW
'owns': '\u220b', # ∋ CONTAINS AS MEMBER
'parallel': '\u2225', # ∥ PARALLEL TO
'perp': '\u27c2', # ⟂ PERPENDICULAR
'pitchfork': '\u22d4', # ⋔ PITCHFORK
'prec': '\u227a', # ≺ PRECEDES
'precapprox': '\u2ab7', # ⪷ PRECEDES ABOVE ALMOST EQUAL TO
'preccurlyeq': '\u227c', # ≼ PRECEDES OR EQUAL TO
'preceq': '\u2aaf', # ⪯ PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
'precnapprox': '\u2ab9', # ⪹ PRECEDES ABOVE NOT ALMOST EQUAL TO
'precnsim': '\u22e8', # ⋨ PRECEDES BUT NOT EQUIVALENT TO
'precsim': '\u227e', # ≾ PRECEDES OR EQUIVALENT TO
'propto': '\u221d', # ∝ PROPORTIONAL TO
'restriction': '\u21be', # ↾ UPWARDS HARPOON WITH BARB RIGHTWARDS
'rightarrow': '\u2192', # → RIGHTWARDS ARROW
'rightarrowtail': '\u21a3', # ↣ RIGHTWARDS ARROW WITH TAIL
'rightarrowtriangle': '\u21fe', # ⇾ RIGHTWARDS OPEN-HEADED ARROW
'rightbarharpoon': '\u296c', # ⥬ RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH
'rightharpoondown': '\u21c1', # ⇁ RIGHTWARDS HARPOON WITH BARB DOWNWARDS
'rightharpoonup': '\u21c0', # ⇀ RIGHTWARDS HARPOON WITH BARB UPWARDS
'rightleftarrows': '\u21c4', # ⇄ RIGHTWARDS ARROW OVER LEFTWARDS ARROW
'rightleftharpoon': '\u294b', # ⥋ LEFT BARB DOWN RIGHT BARB UP HARPOON
'rightleftharpoons': '\u21cc', # ⇌ RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
'rightrightarrows': '\u21c9', # ⇉ RIGHTWARDS PAIRED ARROWS
'rightrightharpoons': '\u2964', # ⥤ RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN
'rightslice': '\u2aa7', # ⪧ GREATER-THAN CLOSED BY CURVE
'rightsquigarrow': '\u21dd', # ⇝ RIGHTWARDS SQUIGGLE ARROW
'risingdotseq': '\u2253', # ≓ IMAGE OF OR APPROXIMATELY EQUAL TO
'searrow': '\u2198', # ↘ SOUTH EAST ARROW
'sim': '\u223c', # TILDE OPERATOR
'simeq': '\u2243', # ≃ ASYMPTOTICALLY EQUAL TO
'smallfrown': '\u2322', # ⌢ FROWN
'smallsmile': '\u2323', # ⌣ SMILE
'smile': '\u2323', # ⌣ SMILE
'sqsubset': '\u228f', # ⊏ SQUARE IMAGE OF
'sqsubseteq': '\u2291', # ⊑ SQUARE IMAGE OF OR EQUAL TO
'sqsupset': '\u2290', # ⊐ SQUARE ORIGINAL OF
'sqsupseteq': '\u2292', # ⊒ SQUARE ORIGINAL OF OR EQUAL TO
'subset': '\u2282', # ⊂ SUBSET OF
'subseteq': '\u2286', # ⊆ SUBSET OF OR EQUAL TO
'subseteqq': '\u2ac5', # ⫅ SUBSET OF ABOVE EQUALS SIGN
'subsetneq': '\u228a', # ⊊ SUBSET OF WITH NOT EQUAL TO
'subsetneqq': '\u2acb', # ⫋ SUBSET OF ABOVE NOT EQUAL TO
'succ': '\u227b', # ≻ SUCCEEDS
'succapprox': '\u2ab8', # ⪸ SUCCEEDS ABOVE ALMOST EQUAL TO
'succcurlyeq': '\u227d', # ≽ SUCCEEDS OR EQUAL TO
'succeq': '\u2ab0', # ⪰ SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
'succnapprox': '\u2aba', # ⪺ SUCCEEDS ABOVE NOT ALMOST EQUAL TO
'succnsim': '\u22e9', # ⋩ SUCCEEDS BUT NOT EQUIVALENT TO
'succsim': '\u227f', # ≿ SUCCEEDS OR EQUIVALENT TO
'supset': '\u2283', # ⊃ SUPERSET OF
'supseteq': '\u2287', # ⊇ SUPERSET OF OR EQUAL TO
'supseteqq': '\u2ac6', # ⫆ SUPERSET OF ABOVE EQUALS SIGN
'supsetneq': '\u228b', # ⊋ SUPERSET OF WITH NOT EQUAL TO
'supsetneqq': '\u2acc', # ⫌ SUPERSET OF ABOVE NOT EQUAL TO
'swarrow': '\u2199', # ↙ SOUTH WEST ARROW
'to': '\u2192', # → RIGHTWARDS ARROW
'trianglelefteq': '\u22b4', # ⊴ NORMAL SUBGROUP OF OR EQUAL TO
'triangleq': '\u225c', # ≜ DELTA EQUAL TO
'trianglerighteq': '\u22b5', # ⊵ CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
'twoheadleftarrow': '\u219e', # ↞ LEFTWARDS TWO HEADED ARROW
'twoheadrightarrow': '\u21a0', # ↠ RIGHTWARDS TWO HEADED ARROW
'uparrow': '\u2191', # ↑ UPWARDS ARROW
'updownarrow': '\u2195', # ↕ UP DOWN ARROW
'updownarrows': '\u21c5', # ⇅ UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW
'updownharpoons': '\u296e', # ⥮ UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
'upharpoonleft': '\u21bf', # ↿ UPWARDS HARPOON WITH BARB LEFTWARDS
'upharpoonright': '\u21be', # ↾ UPWARDS HARPOON WITH BARB RIGHTWARDS
'upuparrows': '\u21c8', # ⇈ UPWARDS PAIRED ARROWS
'upupharpoons': '\u2963', # ⥣ UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
'vDash': '\u22a8', # ⊨ TRUE
'varpropto': '\u221d', # ∝ PROPORTIONAL TO
'vartriangleleft': '\u22b2', # ⊲ NORMAL SUBGROUP OF
'vartriangleright': '\u22b3', # ⊳ CONTAINS AS NORMAL SUBGROUP
'vdash': '\u22a2', # ⊢ RIGHT TACK
'vdots': '\u22ee', # ⋮ VERTICAL ELLIPSIS
}
mathunder = {
'underbrace': '\u23df', # ⏟ BOTTOM CURLY BRACKET
}
space = {
':': '\u205f', # MEDIUM MATHEMATICAL SPACE
'medspace': '\u205f', # MEDIUM MATHEMATICAL SPACE
'quad': '\u2001', # EM QUAD
}

View File

@@ -0,0 +1,788 @@
# LaTeX math to Unicode symbols translation table
# for use with the translate() method of unicode objects.
# Generated with ``write_unichar2tex.py`` from the data in
# http://milde.users.sourceforge.net/LUCR/Math/
# Includes commands from: standard LaTeX, amssymb, amsmath
uni2tex_table = {
160: '~',
163: '\\pounds ',
165: '\\yen ',
172: '\\neg ',
174: '\\circledR ',
177: '\\pm ',
215: '\\times ',
240: '\\eth ',
247: '\\div ',
305: '\\imath ',
567: '\\jmath ',
915: '\\Gamma ',
916: '\\Delta ',
920: '\\Theta ',
923: '\\Lambda ',
926: '\\Xi ',
928: '\\Pi ',
931: '\\Sigma ',
933: '\\Upsilon ',
934: '\\Phi ',
936: '\\Psi ',
937: '\\Omega ',
945: '\\alpha ',
946: '\\beta ',
947: '\\gamma ',
948: '\\delta ',
949: '\\varepsilon ',
950: '\\zeta ',
951: '\\eta ',
952: '\\theta ',
953: '\\iota ',
954: '\\kappa ',
955: '\\lambda ',
956: '\\mu ',
957: '\\nu ',
958: '\\xi ',
960: '\\pi ',
961: '\\rho ',
962: '\\varsigma ',
963: '\\sigma ',
964: '\\tau ',
965: '\\upsilon ',
966: '\\varphi ',
967: '\\chi ',
968: '\\psi ',
969: '\\omega ',
977: '\\vartheta ',
981: '\\phi ',
982: '\\varpi ',
989: '\\digamma ',
1014: '\\backepsilon ',
8193: '\\quad ',
8214: '\\| ',
8224: '\\dagger ',
8225: '\\ddagger ',
8230: '\\ldots ',
8242: '\\prime ',
8245: '\\backprime ',
8287: '\\: ',
8450: '\\mathbb{C}',
8459: '\\mathcal{H}',
8460: '\\mathfrak{H}',
8461: '\\mathbb{H}',
8463: '\\hslash ',
8464: '\\mathcal{I}',
8465: '\\Im ',
8466: '\\mathcal{L}',
8467: '\\ell ',
8469: '\\mathbb{N}',
8472: '\\wp ',
8473: '\\mathbb{P}',
8474: '\\mathbb{Q}',
8475: '\\mathcal{R}',
8476: '\\Re ',
8477: '\\mathbb{R}',
8484: '\\mathbb{Z}',
8487: '\\mho ',
8488: '\\mathfrak{Z}',
8492: '\\mathcal{B}',
8493: '\\mathfrak{C}',
8496: '\\mathcal{E}',
8497: '\\mathcal{F}',
8498: '\\Finv ',
8499: '\\mathcal{M}',
8501: '\\aleph ',
8502: '\\beth ',
8503: '\\gimel ',
8504: '\\daleth ',
8592: '\\leftarrow ',
8593: '\\uparrow ',
8594: '\\rightarrow ',
8595: '\\downarrow ',
8596: '\\leftrightarrow ',
8597: '\\updownarrow ',
8598: '\\nwarrow ',
8599: '\\nearrow ',
8600: '\\searrow ',
8601: '\\swarrow ',
8602: '\\nleftarrow ',
8603: '\\nrightarrow ',
8606: '\\twoheadleftarrow ',
8608: '\\twoheadrightarrow ',
8610: '\\leftarrowtail ',
8611: '\\rightarrowtail ',
8614: '\\mapsto ',
8617: '\\hookleftarrow ',
8618: '\\hookrightarrow ',
8619: '\\looparrowleft ',
8620: '\\looparrowright ',
8621: '\\leftrightsquigarrow ',
8622: '\\nleftrightarrow ',
8624: '\\Lsh ',
8625: '\\Rsh ',
8630: '\\curvearrowleft ',
8631: '\\curvearrowright ',
8634: '\\circlearrowleft ',
8635: '\\circlearrowright ',
8636: '\\leftharpoonup ',
8637: '\\leftharpoondown ',
8638: '\\upharpoonright ',
8639: '\\upharpoonleft ',
8640: '\\rightharpoonup ',
8641: '\\rightharpoondown ',
8642: '\\downharpoonright ',
8643: '\\downharpoonleft ',
8644: '\\rightleftarrows ',
8646: '\\leftrightarrows ',
8647: '\\leftleftarrows ',
8648: '\\upuparrows ',
8649: '\\rightrightarrows ',
8650: '\\downdownarrows ',
8651: '\\leftrightharpoons ',
8652: '\\rightleftharpoons ',
8653: '\\nLeftarrow ',
8654: '\\nLeftrightarrow ',
8655: '\\nRightarrow ',
8656: '\\Leftarrow ',
8657: '\\Uparrow ',
8658: '\\Rightarrow ',
8659: '\\Downarrow ',
8660: '\\Leftrightarrow ',
8661: '\\Updownarrow ',
8666: '\\Lleftarrow ',
8667: '\\Rrightarrow ',
8669: '\\rightsquigarrow ',
8672: '\\dashleftarrow ',
8674: '\\dashrightarrow ',
8704: '\\forall ',
8705: '\\complement ',
8706: '\\partial ',
8707: '\\exists ',
8708: '\\nexists ',
8709: '\\varnothing ',
8711: '\\nabla ',
8712: '\\in ',
8713: '\\notin ',
8715: '\\ni ',
8719: '\\prod ',
8720: '\\coprod ',
8721: '\\sum ',
8722: '-',
8723: '\\mp ',
8724: '\\dotplus ',
8725: '\\slash ',
8726: '\\smallsetminus ',
8727: '\\ast ',
8728: '\\circ ',
8729: '\\bullet ',
8730: '\\sqrt ',
8731: '\\sqrt[3] ',
8732: '\\sqrt[4] ',
8733: '\\propto ',
8734: '\\infty ',
8736: '\\angle ',
8737: '\\measuredangle ',
8738: '\\sphericalangle ',
8739: '\\mid ',
8740: '\\nmid ',
8741: '\\parallel ',
8742: '\\nparallel ',
8743: '\\wedge ',
8744: '\\vee ',
8745: '\\cap ',
8746: '\\cup ',
8747: '\\int ',
8748: '\\iint ',
8749: '\\iiint ',
8750: '\\oint ',
8756: '\\therefore ',
8757: '\\because ',
8758: ':',
8764: '\\sim ',
8765: '\\backsim ',
8768: '\\wr ',
8769: '\\nsim ',
8770: '\\eqsim ',
8771: '\\simeq ',
8773: '\\cong ',
8775: '\\ncong ',
8776: '\\approx ',
8778: '\\approxeq ',
8781: '\\asymp ',
8782: '\\Bumpeq ',
8783: '\\bumpeq ',
8784: '\\doteq ',
8785: '\\Doteq ',
8786: '\\fallingdotseq ',
8787: '\\risingdotseq ',
8790: '\\eqcirc ',
8791: '\\circeq ',
8796: '\\triangleq ',
8800: '\\neq ',
8801: '\\equiv ',
8804: '\\leq ',
8805: '\\geq ',
8806: '\\leqq ',
8807: '\\geqq ',
8808: '\\lneqq ',
8809: '\\gneqq ',
8810: '\\ll ',
8811: '\\gg ',
8812: '\\between ',
8814: '\\nless ',
8815: '\\ngtr ',
8816: '\\nleq ',
8817: '\\ngeq ',
8818: '\\lesssim ',
8819: '\\gtrsim ',
8822: '\\lessgtr ',
8823: '\\gtrless ',
8826: '\\prec ',
8827: '\\succ ',
8828: '\\preccurlyeq ',
8829: '\\succcurlyeq ',
8830: '\\precsim ',
8831: '\\succsim ',
8832: '\\nprec ',
8833: '\\nsucc ',
8834: '\\subset ',
8835: '\\supset ',
8838: '\\subseteq ',
8839: '\\supseteq ',
8840: '\\nsubseteq ',
8841: '\\nsupseteq ',
8842: '\\subsetneq ',
8843: '\\supsetneq ',
8846: '\\uplus ',
8847: '\\sqsubset ',
8848: '\\sqsupset ',
8849: '\\sqsubseteq ',
8850: '\\sqsupseteq ',
8851: '\\sqcap ',
8852: '\\sqcup ',
8853: '\\oplus ',
8854: '\\ominus ',
8855: '\\otimes ',
8856: '\\oslash ',
8857: '\\odot ',
8858: '\\circledcirc ',
8859: '\\circledast ',
8861: '\\circleddash ',
8862: '\\boxplus ',
8863: '\\boxminus ',
8864: '\\boxtimes ',
8865: '\\boxdot ',
8866: '\\vdash ',
8867: '\\dashv ',
8868: '\\top ',
8869: '\\bot ',
8871: '\\models ',
8872: '\\vDash ',
8873: '\\Vdash ',
8874: '\\Vvdash ',
8876: '\\nvdash ',
8877: '\\nvDash ',
8878: '\\nVdash ',
8879: '\\nVDash ',
8882: '\\vartriangleleft ',
8883: '\\vartriangleright ',
8884: '\\trianglelefteq ',
8885: '\\trianglerighteq ',
8888: '\\multimap ',
8890: '\\intercal ',
8891: '\\veebar ',
8892: '\\barwedge ',
8896: '\\bigwedge ',
8897: '\\bigvee ',
8898: '\\bigcap ',
8899: '\\bigcup ',
8900: '\\diamond ',
8901: '\\cdot ',
8902: '\\star ',
8903: '\\divideontimes ',
8904: '\\bowtie ',
8905: '\\ltimes ',
8906: '\\rtimes ',
8907: '\\leftthreetimes ',
8908: '\\rightthreetimes ',
8909: '\\backsimeq ',
8910: '\\curlyvee ',
8911: '\\curlywedge ',
8912: '\\Subset ',
8913: '\\Supset ',
8914: '\\Cap ',
8915: '\\Cup ',
8916: '\\pitchfork ',
8918: '\\lessdot ',
8919: '\\gtrdot ',
8920: '\\lll ',
8921: '\\ggg ',
8922: '\\lesseqgtr ',
8923: '\\gtreqless ',
8926: '\\curlyeqprec ',
8927: '\\curlyeqsucc ',
8928: '\\npreceq ',
8929: '\\nsucceq ',
8934: '\\lnsim ',
8935: '\\gnsim ',
8936: '\\precnsim ',
8937: '\\succnsim ',
8938: '\\ntriangleleft ',
8939: '\\ntriangleright ',
8940: '\\ntrianglelefteq ',
8941: '\\ntrianglerighteq ',
8942: '\\vdots ',
8943: '\\cdots ',
8945: '\\ddots ',
8968: '\\lceil ',
8969: '\\rceil ',
8970: '\\lfloor ',
8971: '\\rfloor ',
8988: '\\ulcorner ',
8989: '\\urcorner ',
8990: '\\llcorner ',
8991: '\\lrcorner ',
8994: '\\frown ',
8995: '\\smile ',
9182: '\\overbrace ',
9183: '\\underbrace ',
9651: '\\bigtriangleup ',
9655: '\\rhd ',
9661: '\\bigtriangledown ',
9665: '\\lhd ',
9671: '\\Diamond ',
9674: '\\lozenge ',
9723: '\\square ',
9724: '\\blacksquare ',
9733: '\\bigstar ',
9824: '\\spadesuit ',
9825: '\\heartsuit ',
9826: '\\diamondsuit ',
9827: '\\clubsuit ',
9837: '\\flat ',
9838: '\\natural ',
9839: '\\sharp ',
10003: '\\checkmark ',
10016: '\\maltese ',
10178: '\\perp ',
10216: '\\langle ',
10217: '\\rangle ',
10222: '\\lgroup ',
10223: '\\rgroup ',
10229: '\\longleftarrow ',
10230: '\\longrightarrow ',
10231: '\\longleftrightarrow ',
10232: '\\Longleftarrow ',
10233: '\\Longrightarrow ',
10234: '\\Longleftrightarrow ',
10236: '\\longmapsto ',
10731: '\\blacklozenge ',
10741: '\\setminus ',
10752: '\\bigodot ',
10753: '\\bigoplus ',
10754: '\\bigotimes ',
10756: '\\biguplus ',
10758: '\\bigsqcup ',
10764: '\\iiiint ',
10781: '\\Join ',
10815: '\\amalg ',
10846: '\\doublebarwedge ',
10877: '\\leqslant ',
10878: '\\geqslant ',
10885: '\\lessapprox ',
10886: '\\gtrapprox ',
10887: '\\lneq ',
10888: '\\gneq ',
10889: '\\lnapprox ',
10890: '\\gnapprox ',
10891: '\\lesseqqgtr ',
10892: '\\gtreqqless ',
10901: '\\eqslantless ',
10902: '\\eqslantgtr ',
10927: '\\preceq ',
10928: '\\succeq ',
10935: '\\precapprox ',
10936: '\\succapprox ',
10937: '\\precnapprox ',
10938: '\\succnapprox ',
10949: '\\subseteqq ',
10950: '\\supseteqq ',
10955: '\\subsetneqq ',
10956: '\\supsetneqq ',
119808: '\\mathbf{A}',
119809: '\\mathbf{B}',
119810: '\\mathbf{C}',
119811: '\\mathbf{D}',
119812: '\\mathbf{E}',
119813: '\\mathbf{F}',
119814: '\\mathbf{G}',
119815: '\\mathbf{H}',
119816: '\\mathbf{I}',
119817: '\\mathbf{J}',
119818: '\\mathbf{K}',
119819: '\\mathbf{L}',
119820: '\\mathbf{M}',
119821: '\\mathbf{N}',
119822: '\\mathbf{O}',
119823: '\\mathbf{P}',
119824: '\\mathbf{Q}',
119825: '\\mathbf{R}',
119826: '\\mathbf{S}',
119827: '\\mathbf{T}',
119828: '\\mathbf{U}',
119829: '\\mathbf{V}',
119830: '\\mathbf{W}',
119831: '\\mathbf{X}',
119832: '\\mathbf{Y}',
119833: '\\mathbf{Z}',
119834: '\\mathbf{a}',
119835: '\\mathbf{b}',
119836: '\\mathbf{c}',
119837: '\\mathbf{d}',
119838: '\\mathbf{e}',
119839: '\\mathbf{f}',
119840: '\\mathbf{g}',
119841: '\\mathbf{h}',
119842: '\\mathbf{i}',
119843: '\\mathbf{j}',
119844: '\\mathbf{k}',
119845: '\\mathbf{l}',
119846: '\\mathbf{m}',
119847: '\\mathbf{n}',
119848: '\\mathbf{o}',
119849: '\\mathbf{p}',
119850: '\\mathbf{q}',
119851: '\\mathbf{r}',
119852: '\\mathbf{s}',
119853: '\\mathbf{t}',
119854: '\\mathbf{u}',
119855: '\\mathbf{v}',
119856: '\\mathbf{w}',
119857: '\\mathbf{x}',
119858: '\\mathbf{y}',
119859: '\\mathbf{z}',
119860: 'A',
119861: 'B',
119862: 'C',
119863: 'D',
119864: 'E',
119865: 'F',
119866: 'G',
119867: 'H',
119868: 'I',
119869: 'J',
119870: 'K',
119871: 'L',
119872: 'M',
119873: 'N',
119874: 'O',
119875: 'P',
119876: 'Q',
119877: 'R',
119878: 'S',
119879: 'T',
119880: 'U',
119881: 'V',
119882: 'W',
119883: 'X',
119884: 'Y',
119885: 'Z',
119886: 'a',
119887: 'b',
119888: 'c',
119889: 'd',
119890: 'e',
119891: 'f',
119892: 'g',
119894: 'i',
119895: 'j',
119896: 'k',
119897: 'l',
119898: 'm',
119899: 'n',
119900: 'o',
119901: 'p',
119902: 'q',
119903: 'r',
119904: 's',
119905: 't',
119906: 'u',
119907: 'v',
119908: 'w',
119909: 'x',
119910: 'y',
119911: 'z',
119964: '\\mathcal{A}',
119966: '\\mathcal{C}',
119967: '\\mathcal{D}',
119970: '\\mathcal{G}',
119973: '\\mathcal{J}',
119974: '\\mathcal{K}',
119977: '\\mathcal{N}',
119978: '\\mathcal{O}',
119979: '\\mathcal{P}',
119980: '\\mathcal{Q}',
119982: '\\mathcal{S}',
119983: '\\mathcal{T}',
119984: '\\mathcal{U}',
119985: '\\mathcal{V}',
119986: '\\mathcal{W}',
119987: '\\mathcal{X}',
119988: '\\mathcal{Y}',
119989: '\\mathcal{Z}',
120068: '\\mathfrak{A}',
120069: '\\mathfrak{B}',
120071: '\\mathfrak{D}',
120072: '\\mathfrak{E}',
120073: '\\mathfrak{F}',
120074: '\\mathfrak{G}',
120077: '\\mathfrak{J}',
120078: '\\mathfrak{K}',
120079: '\\mathfrak{L}',
120080: '\\mathfrak{M}',
120081: '\\mathfrak{N}',
120082: '\\mathfrak{O}',
120083: '\\mathfrak{P}',
120084: '\\mathfrak{Q}',
120086: '\\mathfrak{S}',
120087: '\\mathfrak{T}',
120088: '\\mathfrak{U}',
120089: '\\mathfrak{V}',
120090: '\\mathfrak{W}',
120091: '\\mathfrak{X}',
120092: '\\mathfrak{Y}',
120094: '\\mathfrak{a}',
120095: '\\mathfrak{b}',
120096: '\\mathfrak{c}',
120097: '\\mathfrak{d}',
120098: '\\mathfrak{e}',
120099: '\\mathfrak{f}',
120100: '\\mathfrak{g}',
120101: '\\mathfrak{h}',
120102: '\\mathfrak{i}',
120103: '\\mathfrak{j}',
120104: '\\mathfrak{k}',
120105: '\\mathfrak{l}',
120106: '\\mathfrak{m}',
120107: '\\mathfrak{n}',
120108: '\\mathfrak{o}',
120109: '\\mathfrak{p}',
120110: '\\mathfrak{q}',
120111: '\\mathfrak{r}',
120112: '\\mathfrak{s}',
120113: '\\mathfrak{t}',
120114: '\\mathfrak{u}',
120115: '\\mathfrak{v}',
120116: '\\mathfrak{w}',
120117: '\\mathfrak{x}',
120118: '\\mathfrak{y}',
120119: '\\mathfrak{z}',
120120: '\\mathbb{A}',
120121: '\\mathbb{B}',
120123: '\\mathbb{D}',
120124: '\\mathbb{E}',
120125: '\\mathbb{F}',
120126: '\\mathbb{G}',
120128: '\\mathbb{I}',
120129: '\\mathbb{J}',
120130: '\\mathbb{K}',
120131: '\\mathbb{L}',
120132: '\\mathbb{M}',
120134: '\\mathbb{O}',
120138: '\\mathbb{S}',
120139: '\\mathbb{T}',
120140: '\\mathbb{U}',
120141: '\\mathbb{V}',
120142: '\\mathbb{W}',
120143: '\\mathbb{X}',
120144: '\\mathbb{Y}',
120156: '\\Bbbk ',
120224: '\\mathsf{A}',
120225: '\\mathsf{B}',
120226: '\\mathsf{C}',
120227: '\\mathsf{D}',
120228: '\\mathsf{E}',
120229: '\\mathsf{F}',
120230: '\\mathsf{G}',
120231: '\\mathsf{H}',
120232: '\\mathsf{I}',
120233: '\\mathsf{J}',
120234: '\\mathsf{K}',
120235: '\\mathsf{L}',
120236: '\\mathsf{M}',
120237: '\\mathsf{N}',
120238: '\\mathsf{O}',
120239: '\\mathsf{P}',
120240: '\\mathsf{Q}',
120241: '\\mathsf{R}',
120242: '\\mathsf{S}',
120243: '\\mathsf{T}',
120244: '\\mathsf{U}',
120245: '\\mathsf{V}',
120246: '\\mathsf{W}',
120247: '\\mathsf{X}',
120248: '\\mathsf{Y}',
120249: '\\mathsf{Z}',
120250: '\\mathsf{a}',
120251: '\\mathsf{b}',
120252: '\\mathsf{c}',
120253: '\\mathsf{d}',
120254: '\\mathsf{e}',
120255: '\\mathsf{f}',
120256: '\\mathsf{g}',
120257: '\\mathsf{h}',
120258: '\\mathsf{i}',
120259: '\\mathsf{j}',
120260: '\\mathsf{k}',
120261: '\\mathsf{l}',
120262: '\\mathsf{m}',
120263: '\\mathsf{n}',
120264: '\\mathsf{o}',
120265: '\\mathsf{p}',
120266: '\\mathsf{q}',
120267: '\\mathsf{r}',
120268: '\\mathsf{s}',
120269: '\\mathsf{t}',
120270: '\\mathsf{u}',
120271: '\\mathsf{v}',
120272: '\\mathsf{w}',
120273: '\\mathsf{x}',
120274: '\\mathsf{y}',
120275: '\\mathsf{z}',
120432: '\\mathtt{A}',
120433: '\\mathtt{B}',
120434: '\\mathtt{C}',
120435: '\\mathtt{D}',
120436: '\\mathtt{E}',
120437: '\\mathtt{F}',
120438: '\\mathtt{G}',
120439: '\\mathtt{H}',
120440: '\\mathtt{I}',
120441: '\\mathtt{J}',
120442: '\\mathtt{K}',
120443: '\\mathtt{L}',
120444: '\\mathtt{M}',
120445: '\\mathtt{N}',
120446: '\\mathtt{O}',
120447: '\\mathtt{P}',
120448: '\\mathtt{Q}',
120449: '\\mathtt{R}',
120450: '\\mathtt{S}',
120451: '\\mathtt{T}',
120452: '\\mathtt{U}',
120453: '\\mathtt{V}',
120454: '\\mathtt{W}',
120455: '\\mathtt{X}',
120456: '\\mathtt{Y}',
120457: '\\mathtt{Z}',
120458: '\\mathtt{a}',
120459: '\\mathtt{b}',
120460: '\\mathtt{c}',
120461: '\\mathtt{d}',
120462: '\\mathtt{e}',
120463: '\\mathtt{f}',
120464: '\\mathtt{g}',
120465: '\\mathtt{h}',
120466: '\\mathtt{i}',
120467: '\\mathtt{j}',
120468: '\\mathtt{k}',
120469: '\\mathtt{l}',
120470: '\\mathtt{m}',
120471: '\\mathtt{n}',
120472: '\\mathtt{o}',
120473: '\\mathtt{p}',
120474: '\\mathtt{q}',
120475: '\\mathtt{r}',
120476: '\\mathtt{s}',
120477: '\\mathtt{t}',
120478: '\\mathtt{u}',
120479: '\\mathtt{v}',
120480: '\\mathtt{w}',
120481: '\\mathtt{x}',
120482: '\\mathtt{y}',
120483: '\\mathtt{z}',
120484: '\\imath ',
120485: '\\jmath ',
120490: '\\mathbf{\\Gamma}',
120491: '\\mathbf{\\Delta}',
120495: '\\mathbf{\\Theta}',
120498: '\\mathbf{\\Lambda}',
120501: '\\mathbf{\\Xi}',
120503: '\\mathbf{\\Pi}',
120506: '\\mathbf{\\Sigma}',
120508: '\\mathbf{\\Upsilon}',
120509: '\\mathbf{\\Phi}',
120511: '\\mathbf{\\Psi}',
120512: '\\mathbf{\\Omega}',
120548: '\\mathit{\\Gamma}',
120549: '\\mathit{\\Delta}',
120553: '\\mathit{\\Theta}',
120556: '\\mathit{\\Lambda}',
120559: '\\mathit{\\Xi}',
120561: '\\mathit{\\Pi}',
120564: '\\mathit{\\Sigma}',
120566: '\\mathit{\\Upsilon}',
120567: '\\mathit{\\Phi}',
120569: '\\mathit{\\Psi}',
120570: '\\mathit{\\Omega}',
120572: '\\alpha ',
120573: '\\beta ',
120574: '\\gamma ',
120575: '\\delta ',
120576: '\\varepsilon ',
120577: '\\zeta ',
120578: '\\eta ',
120579: '\\theta ',
120580: '\\iota ',
120581: '\\kappa ',
120582: '\\lambda ',
120583: '\\mu ',
120584: '\\nu ',
120585: '\\xi ',
120587: '\\pi ',
120588: '\\rho ',
120589: '\\varsigma ',
120590: '\\sigma ',
120591: '\\tau ',
120592: '\\upsilon ',
120593: '\\varphi ',
120594: '\\chi ',
120595: '\\psi ',
120596: '\\omega ',
120597: '\\partial ',
120598: '\\epsilon ',
120599: '\\vartheta ',
120600: '\\varkappa ',
120601: '\\phi ',
120602: '\\varrho ',
120603: '\\varpi ',
120782: '\\mathbf{0}',
120783: '\\mathbf{1}',
120784: '\\mathbf{2}',
120785: '\\mathbf{3}',
120786: '\\mathbf{4}',
120787: '\\mathbf{5}',
120788: '\\mathbf{6}',
120789: '\\mathbf{7}',
120790: '\\mathbf{8}',
120791: '\\mathbf{9}',
120802: '\\mathsf{0}',
120803: '\\mathsf{1}',
120804: '\\mathsf{2}',
120805: '\\mathsf{3}',
120806: '\\mathsf{4}',
120807: '\\mathsf{5}',
120808: '\\mathsf{6}',
120809: '\\mathsf{7}',
120810: '\\mathsf{8}',
120811: '\\mathsf{9}',
120822: '\\mathtt{0}',
120823: '\\mathtt{1}',
120824: '\\mathtt{2}',
120825: '\\mathtt{3}',
120826: '\\mathtt{4}',
120827: '\\mathtt{5}',
120828: '\\mathtt{6}',
120829: '\\mathtt{7}',
120830: '\\mathtt{8}',
120831: '\\mathtt{9}',
}

View File

@@ -0,0 +1,122 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# :Id: $Id: punctuation_chars.py 8016 2017-01-17 15:06:17Z milde $
# :Copyright: © 2011, 2017 Günter Milde.
# :License: Released under the terms of the `2-Clause BSD license`_, in short:
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.
# This file is offered as-is, without any warranty.
#
# .. _2-Clause BSD license: http://www.spdx.org/licenses/BSD-2-Clause
#
# This file is generated by
# ``docutils/tools/dev/generate_punctuation_chars.py``.
# ::
import sys, re
import unicodedata
"""Docutils character category patterns.
Patterns for the implementation of the `inline markup recognition rules`_
in the reStructuredText parser `docutils.parsers.rst.states.py` based
on Unicode character categories.
The patterns are used inside ``[ ]`` in regular expressions.
Rule (5) requires determination of matching open/close pairs. However, the
pairing of open/close quotes is ambiguous due to different typographic
conventions in different languages. The ``quote_pairs`` function tests
whether two characters form an open/close pair.
The patterns are generated by
``docutils/tools/dev/generate_punctuation_chars.py`` to prevent dependence
on the Python version and avoid the time-consuming generation with every
Docutils run. See there for motives and implementation details.
The category of some characters changed with the development of the
Unicode standard. The current lists are generated with the help of the
"unicodedata" module of Python 2.7.13 (based on Unicode version 5.2.0).
.. _inline markup recognition rules:
http://docutils.sf.net/docs/ref/rst/restructuredtext.html#inline-markup-recognition-rules
"""
openers = ('"\'(<\\[{\u0f3a\u0f3c\u169b\u2045\u207d\u208d\u2329\u2768'
'\u276a\u276c\u276e\u2770\u2772\u2774\u27c5\u27e6\u27e8\u27ea'
'\u27ec\u27ee\u2983\u2985\u2987\u2989\u298b\u298d\u298f\u2991'
'\u2993\u2995\u2997\u29d8\u29da\u29fc\u2e22\u2e24\u2e26\u2e28'
'\u3008\u300a\u300c\u300e\u3010\u3014\u3016\u3018\u301a\u301d'
'\u301d\ufd3e\ufe17\ufe35\ufe37\ufe39\ufe3b\ufe3d\ufe3f\ufe41'
'\ufe43\ufe47\ufe59\ufe5b\ufe5d\uff08\uff3b\uff5b\uff5f\uff62'
'\xab\u2018\u201c\u2039\u2e02\u2e04\u2e09\u2e0c\u2e1c\u2e20'
'\u201a\u201e\xbb\u2019\u201d\u203a\u2e03\u2e05\u2e0a\u2e0d'
'\u2e1d\u2e21\u201b\u201f')
closers = ('"\')>\\]}\u0f3b\u0f3d\u169c\u2046\u207e\u208e\u232a\u2769'
'\u276b\u276d\u276f\u2771\u2773\u2775\u27c6\u27e7\u27e9\u27eb'
'\u27ed\u27ef\u2984\u2986\u2988\u298a\u298c\u298e\u2990\u2992'
'\u2994\u2996\u2998\u29d9\u29db\u29fd\u2e23\u2e25\u2e27\u2e29'
'\u3009\u300b\u300d\u300f\u3011\u3015\u3017\u3019\u301b\u301e'
'\u301f\ufd3f\ufe18\ufe36\ufe38\ufe3a\ufe3c\ufe3e\ufe40\ufe42'
'\ufe44\ufe48\ufe5a\ufe5c\ufe5e\uff09\uff3d\uff5d\uff60\uff63'
'\xbb\u2019\u201d\u203a\u2e03\u2e05\u2e0a\u2e0d\u2e1d\u2e21'
'\u201b\u201f\xab\u2018\u201c\u2039\u2e02\u2e04\u2e09\u2e0c'
'\u2e1c\u2e20\u201a\u201e')
delimiters = ('\\-/:\u058a\xa1\xb7\xbf\u037e\u0387\u055a-\u055f\u0589'
'\u05be\u05c0\u05c3\u05c6\u05f3\u05f4\u0609\u060a\u060c'
'\u060d\u061b\u061e\u061f\u066a-\u066d\u06d4\u0700-\u070d'
'\u07f7-\u07f9\u0830-\u083e\u0964\u0965\u0970\u0df4\u0e4f'
'\u0e5a\u0e5b\u0f04-\u0f12\u0f85\u0fd0-\u0fd4\u104a-\u104f'
'\u10fb\u1361-\u1368\u1400\u166d\u166e\u16eb-\u16ed\u1735'
'\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u180a\u1944\u1945'
'\u19de\u19df\u1a1e\u1a1f\u1aa0-\u1aa6\u1aa8-\u1aad\u1b5a-'
'\u1b60\u1c3b-\u1c3f\u1c7e\u1c7f\u1cd3\u2010-\u2017\u2020-'
'\u2027\u2030-\u2038\u203b-\u203e\u2041-\u2043\u2047-'
'\u2051\u2053\u2055-\u205e\u2cf9-\u2cfc\u2cfe\u2cff\u2e00'
'\u2e01\u2e06-\u2e08\u2e0b\u2e0e-\u2e1b\u2e1e\u2e1f\u2e2a-'
'\u2e2e\u2e30\u2e31\u3001-\u3003\u301c\u3030\u303d\u30a0'
'\u30fb\ua4fe\ua4ff\ua60d-\ua60f\ua673\ua67e\ua6f2-\ua6f7'
'\ua874-\ua877\ua8ce\ua8cf\ua8f8-\ua8fa\ua92e\ua92f\ua95f'
'\ua9c1-\ua9cd\ua9de\ua9df\uaa5c-\uaa5f\uaade\uaadf\uabeb'
'\ufe10-\ufe16\ufe19\ufe30-\ufe32\ufe45\ufe46\ufe49-\ufe4c'
'\ufe50-\ufe52\ufe54-\ufe58\ufe5f-\ufe61\ufe63\ufe68\ufe6a'
'\ufe6b\uff01-\uff03\uff05-\uff07\uff0a\uff0c-\uff0f\uff1a'
'\uff1b\uff1f\uff20\uff3c\uff61\uff64\uff65')
if sys.maxunicode >= 0x10FFFF: # "wide" build
delimiters += ('\U00010100\U00010101\U0001039f\U000103d0\U00010857'
'\U0001091f\U0001093f\U00010a50-\U00010a58\U00010a7f'
'\U00010b39-\U00010b3f\U000110bb\U000110bc\U000110be-'
'\U000110c1\U00012470-\U00012473')
closing_delimiters = '\\\\.,;!?'
# Matching open/close quotes
# --------------------------
quote_pairs = {# open char: matching closing characters # usage example
'\xbb': '\xbb', # » » Swedish
'\u2018': '\u201a', # Albanian/Greek/Turkish
'\u2019': '\u2019', # Swedish
'\u201a': '\u2018\u2019', # German Polish
'\u201c': '\u201e', # “ „ Albanian/Greek/Turkish
'\u201e': '\u201c\u201d', # „ “ German „ ” Polish
'\u201d': '\u201d', # ” ” Swedish
'\u203a': '\u203a', # Swedish
}
"""Additional open/close quote pairs."""
def match_chars(c1, c2):
"""Test whether `c1` and `c2` are a matching open/close character pair.
Matching open/close pairs are at the same position in
`punctuation_chars.openers` and `punctuation_chars.closers`.
The pairing of open/close quotes is ambiguous due to different
typographic conventions in different languages,
so we test for additional matches stored in `quote_pairs`.
"""
try:
i = openers.index(c1)
except ValueError: # c1 not in openers
return False
return c2 == closers[i] or c2 in quote_pairs.get(c1, '')

View File

@@ -0,0 +1,81 @@
"""Convert to and from Roman numerals"""
__author__ = "Mark Pilgrim (f8dy@diveintopython.org)"
__version__ = "1.4"
__date__ = "8 August 2001"
__copyright__ = """Copyright (c) 2001 Mark Pilgrim
This program is part of "Dive Into Python", a free Python tutorial for
experienced programmers. Visit http://diveintopython.org/ for the
latest version.
This program is free software; you can redistribute it and/or modify
it under the terms of the Python 2.1.1 license, available at
http://www.python.org/2.1.1/license.html
"""
import re
#Define exceptions
class RomanError(Exception): pass
class OutOfRangeError(RomanError): pass
class NotIntegerError(RomanError): pass
class InvalidRomanNumeralError(RomanError): pass
#Define digit mapping
romanNumeralMap = (('M', 1000),
('CM', 900),
('D', 500),
('CD', 400),
('C', 100),
('XC', 90),
('L', 50),
('XL', 40),
('X', 10),
('IX', 9),
('V', 5),
('IV', 4),
('I', 1))
def toRoman(n):
"""convert integer to Roman numeral"""
if not (0 < n < 5000):
raise OutOfRangeError("number out of range (must be 1..4999)")
if int(n) != n:
raise NotIntegerError("decimals can not be converted")
result = ""
for numeral, integer in romanNumeralMap:
while n >= integer:
result += numeral
n -= integer
return result
#Define pattern to detect valid Roman numerals
romanNumeralPattern = re.compile("""
^ # beginning of string
M{0,4} # thousands - 0 to 4 M's
(CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
# or 500-800 (D, followed by 0 to 3 C's)
(XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
# or 50-80 (L, followed by 0 to 3 X's)
(IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
# or 5-8 (V, followed by 0 to 3 I's)
$ # end of string
""" ,re.VERBOSE)
def fromRoman(s):
"""convert Roman numeral to integer"""
if not s:
raise InvalidRomanNumeralError('Input can not be blank')
if not romanNumeralPattern.search(s):
raise InvalidRomanNumeralError('Invalid Roman numeral: %s' % s)
result = 0
index = 0
for numeral, integer in romanNumeralMap:
while s[index:index+len(numeral)] == numeral:
result += integer
index += len(numeral)
return result

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,136 @@
# $Id: urischemes.py 7922 2015-09-22 15:28:09Z milde $
# Author: David Goodger <goodger@python.org>
# Copyright: This module has been placed in the public domain.
"""
`schemes` is a dictionary with lowercase URI addressing schemes as
keys and descriptions as values. It was compiled from the index at
http://www.iana.org/assignments/uri-schemes (revised 2005-11-28)
and an older list at http://www.w3.org/Addressing/schemes.html.
"""
# Many values are blank and should be filled in with useful descriptions.
schemes = {
'about': 'provides information on Navigator',
'acap': 'Application Configuration Access Protocol; RFC 2244',
'addbook': "To add vCard entries to Communicator's Address Book",
'afp': 'Apple Filing Protocol',
'afs': 'Andrew File System global file names',
'aim': 'AOL Instant Messenger',
'callto': 'for NetMeeting links',
'castanet': 'Castanet Tuner URLs for Netcaster',
'chttp': 'cached HTTP supported by RealPlayer',
'cid': 'content identifier; RFC 2392',
'crid': 'TV-Anytime Content Reference Identifier; RFC 4078',
'data': ('allows inclusion of small data items as "immediate" data; '
'RFC 2397'),
'dav': 'Distributed Authoring and Versioning Protocol; RFC 2518',
'dict': 'dictionary service protocol; RFC 2229',
'dns': 'Domain Name System resources',
'eid': ('External ID; non-URL data; general escape mechanism to allow '
'access to information for applications that are too '
'specialized to justify their own schemes'),
'fax': ('a connection to a terminal that can handle telefaxes '
'(facsimiles); RFC 2806'),
'feed' : 'NetNewsWire feed',
'file': 'Host-specific file names; RFC 1738',
'finger': '',
'freenet': '',
'ftp': 'File Transfer Protocol; RFC 1738',
'go': 'go; RFC 3368',
'gopher': 'The Gopher Protocol',
'gsm-sms': ('Global System for Mobile Communications Short Message '
'Service'),
'h323': ('video (audiovisual) communication on local area networks; '
'RFC 3508'),
'h324': ('video and audio communications over low bitrate connections '
'such as POTS modem connections'),
'hdl': 'CNRI handle system',
'hnews': 'an HTTP-tunneling variant of the NNTP news protocol',
'http': 'Hypertext Transfer Protocol; RFC 2616',
'https': 'HTTP over SSL; RFC 2818',
'hydra': 'SubEthaEdit URI. See http://www.codingmonkeys.de/subethaedit.',
'iioploc': 'Internet Inter-ORB Protocol Location?',
'ilu': 'Inter-Language Unification',
'im': 'Instant Messaging; RFC 3860',
'imap': 'Internet Message Access Protocol; RFC 2192',
'info': 'Information Assets with Identifiers in Public Namespaces',
'ior': 'CORBA interoperable object reference',
'ipp': 'Internet Printing Protocol; RFC 3510',
'irc': 'Internet Relay Chat',
'iris.beep': 'iris.beep; RFC 3983',
'iseek' : 'See www.ambrosiasw.com; a little util for OS X.',
'jar': 'Java archive',
'javascript': ('JavaScript code; evaluates the expression after the '
'colon'),
'jdbc': 'JDBC connection URI.',
'ldap': 'Lightweight Directory Access Protocol',
'lifn': '',
'livescript': '',
'lrq': '',
'mailbox': 'Mail folder access',
'mailserver': 'Access to data available from mail servers',
'mailto': 'Electronic mail address; RFC 2368',
'md5': '',
'mid': 'message identifier; RFC 2392',
'mocha': '',
'modem': ('a connection to a terminal that can handle incoming data '
'calls; RFC 2806'),
'mtqp': 'Message Tracking Query Protocol; RFC 3887',
'mupdate': 'Mailbox Update (MUPDATE) Protocol; RFC 3656',
'news': 'USENET news; RFC 1738',
'nfs': 'Network File System protocol; RFC 2224',
'nntp': 'USENET news using NNTP access; RFC 1738',
'opaquelocktoken': 'RFC 2518',
'phone': '',
'pop': 'Post Office Protocol; RFC 2384',
'pop3': 'Post Office Protocol v3',
'pres': 'Presence; RFC 3859',
'printer': '',
'prospero': 'Prospero Directory Service; RFC 4157',
'rdar' : ('URLs found in Darwin source '
'(http://www.opensource.apple.com/darwinsource/).'),
'res': '',
'rtsp': 'real time streaming protocol; RFC 2326',
'rvp': '',
'rwhois': '',
'rx': 'Remote Execution',
'sdp': '',
'service': 'service location; RFC 2609',
'shttp': 'secure hypertext transfer protocol',
'sip': 'Session Initiation Protocol; RFC 3261',
'sips': 'secure session intitiaion protocol; RFC 3261',
'smb': 'SAMBA filesystems.',
'snews': 'For NNTP postings via SSL',
'snmp': 'Simple Network Management Protocol; RFC 4088',
'soap.beep': 'RFC 3288',
'soap.beeps': 'RFC 3288',
'ssh': 'Reference to interactive sessions via ssh.',
't120': 'real time data conferencing (audiographics)',
'tag': 'RFC 4151',
'tcp': '',
'tel': ('a connection to a terminal that handles normal voice '
'telephone calls, a voice mailbox or another voice messaging '
'system or a service that can be operated using DTMF tones; '
'RFC 3966.'),
'telephone': 'telephone',
'telnet': 'Reference to interactive sessions; RFC 4248',
'tftp': 'Trivial File Transfer Protocol; RFC 3617',
'tip': 'Transaction Internet Protocol; RFC 2371',
'tn3270': 'Interactive 3270 emulation sessions',
'tv': '',
'urn': 'Uniform Resource Name; RFC 2141',
'uuid': '',
'vemmi': 'versatile multimedia interface; RFC 2122',
'videotex': '',
'view-source': 'displays HTML code that was generated with JavaScript',
'wais': 'Wide Area Information Servers; RFC 4156',
'whodp': '',
'whois++': 'Distributed directory service.',
'x-man-page': ('Opens man page in Terminal.app on OS X '
'(see macosxhints.com)'),
'xmlrpc.beep': 'RFC 3529',
'xmlrpc.beeps': 'RFC 3529',
'z39.50r': 'Z39.50 Retrieval; RFC 2056',
'z39.50s': 'Z39.50 Session; RFC 2056',}