| 1 | # -*- coding: utf-8 -* |
| 2 | """ |
| 3 | jsMath support for the notebook |
| 4 | |
| 5 | Provides code to parse HTML, changing \$'s and \$\$'s to |
| 6 | <span class="math"> tags to allow jsMath to process them. |
| 7 | |
| 8 | AUTHORS: |
| 9 | |
| 10 | - William Stein (?) -- initial revision |
| 11 | |
| 12 | - Tim Dumol (Oct 6, 2009) -- Added HTMLMathParser. Made `math_parser` skip <script> tags. |
| 13 | |
| 14 | - Reverted HTMLMathParser |
| 15 | |
| 16 | - Edited by John Palmieri, for Flask and MathJax cutover |
| 17 | """ |
| 18 | |
| 19 | ######################################################################## |
| 20 | # Copyright (C) 2008, 2009 William Stein <wstein@gmail.com> |
| 21 | # Distributed under the terms of the GNU General Public License (GPL) |
| 22 | # http://www.gnu.org/licenses/ |
| 23 | ######################################################################## |
| 24 | |
| 25 | |
| 26 | def math_parse(s): |
| 27 | r""" |
| 28 | Turn the HTML-ish string s that can have $$ and $'s in it into |
| 29 | pure HTML. See below for a precise definition of what this means. |
| 30 | |
| 31 | INPUT: |
| 32 | s -- a string |
| 33 | OUTPUT: |
| 34 | a string. |
| 35 | |
| 36 | Do the following: |
| 37 | \begin{verbatim} |
| 38 | * Replace all $ text $'s by |
| 39 | <script type="math/tex"> text </script> |
| 40 | * Replace all $$ text $$'s by |
| 41 | <script type="math/tex; mode=display"> text </script> |
| 42 | * Replace all \$'s by $'s. Note that in |
| 43 | the above two cases nothing is done if the $ |
| 44 | is preceeded by a backslash. |
| 45 | * Replace all \[ text \]'s by |
| 46 | <script type="math/tex; mode=display"> text </script> |
| 47 | \end{verbatim} |
| 48 | |
| 49 | EXAMPLES: |
| 50 | sage: sage.misc.html.math_parse('This is $2+2$.') |
| 51 | 'This is <script type="math/tex">2+2</script>.' |
| 52 | sage: sage.misc.html.math_parse('This is $$2+2$$.') |
| 53 | 'This is <script type="math/tex; mode=display">2+2</script>.' |
| 54 | sage: sage.misc.html.math_parse('This is \\[2+2\\].') |
| 55 | 'This is <script type="math/tex; mode=display">2+2</script>.' |
| 56 | sage: sage.misc.html.math_parse(r'This is \[2+2\].') |
| 57 | 'This is <script type="math/tex; mode=display">2+2</script>.' |
| 58 | |
| 59 | TESTS: |
| 60 | sage: sage.misc.html.math_parse(r'This \$\$is $2+2$.') |
| 61 | 'This $$is <script type="math/tex">2+2</script>.' |
| 62 | """ |
| 63 | # first replace \\[ and \\] by <div class="math"> and </div>, respectively. |
| 64 | while True: |
| 65 | i = s.find('\\[') |
| 66 | if i == -1: |
| 67 | break |
| 68 | else: |
| 69 | s = s[:i] + '<script type="math/tex; mode=display">' + s[i+2:] |
| 70 | j = s.find('\\]') |
| 71 | if j == -1: # missing right-hand delimiter, so add one |
| 72 | s = s + '</script>' |
| 73 | else: |
| 74 | s = s[:j] + '</script>' + s[j+2:] |
| 75 | |
| 76 | # Below t always has the "parsed so far" version of s, and s is |
| 77 | # just the part of the original input s that hasn't been parsed. |
| 78 | t = '' |
| 79 | while True: |
| 80 | i = s.find('$') |
| 81 | if i == -1: |
| 82 | # No dollar signs -- definitely done. |
| 83 | return t + s |
| 84 | elif i > 0 and s[i-1] == '\\': |
| 85 | # A dollar sign with a backslash right before it, so |
| 86 | # we ignore it by sticking it in the parsed string t |
| 87 | # and skip to the next iteration. |
| 88 | t += s[:i-1] + '$' |
| 89 | s = s[i+1:] |
| 90 | continue |
| 91 | elif i+1 < len(s) and s[i+1] == '$': |
| 92 | # Found a math environment. Double dollar sign so display mode. |
| 93 | disp = '; mode=display' |
| 94 | else: |
| 95 | # Found math environment. Single dollar sign so default mode. |
| 96 | disp = '' |
| 97 | |
| 98 | # Now find the matching $ sign and form the html string. |
| 99 | |
| 100 | if len(disp) > 0: |
| 101 | j = s[i+2:].find('$$') |
| 102 | if j == -1: |
| 103 | j = len(s) |
| 104 | s += '$$' |
| 105 | else: |
| 106 | j += i + 2 |
| 107 | txt = s[i+2:j] |
| 108 | else: |
| 109 | j = s[i+2:].find('$') |
| 110 | if j == -1: |
| 111 | j = len(s) |
| 112 | s += '$' |
| 113 | else: |
| 114 | j += i + 2 |
| 115 | txt = s[i+1:j] |
| 116 | |
| 117 | t += s[:i] + '<script type="math/tex%s">%s</script>'%(disp, |
| 118 | ' '.join(txt.splitlines())) |
| 119 | s = s[j+1:] |
| 120 | if len(disp) > 0: |
| 121 | s = s[1:] |
| 122 | return t |