| | 6 | def use_reST(text): |
|---|
| | 7 | """Return True if text includes reST and False otherwise. |
|---|
| | 8 | |
|---|
| | 9 | See http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html |
|---|
| | 10 | for reference. |
|---|
| | 11 | |
|---|
| | 12 | >>> use_reST("String with *emphasis*.") |
|---|
| | 13 | True |
|---|
| | 14 | >>> use_reST("*Multi-word emphasis.*") |
|---|
| | 15 | True |
|---|
| | 16 | >>> use_reST("How about testing **strong string**?") |
|---|
| | 17 | True |
|---|
| | 18 | >>> use_reST("Some *noisy!* punctuation") |
|---|
| | 19 | True |
|---|
| | 20 | >>> use_reST("**characters?**, in the way.") |
|---|
| | 21 | True |
|---|
| | 22 | >>> use_reST("Don\'t forget ``inline literals``.") |
|---|
| | 23 | True |
|---|
| | 24 | >>> use_reST("This is reST (hyperlink_).") |
|---|
| | 25 | True |
|---|
| | 26 | >>> use_reST("This is (`quite long hyperlink`_).") |
|---|
| | 27 | True |
|---|
| | 28 | >>> use_reST("* Bullet\\n* List\\n") |
|---|
| | 29 | True |
|---|
| | 30 | >>> use_reST(":Field: list\\n:indeed: it is\\n") |
|---|
| | 31 | True |
|---|
| | 32 | |
|---|
| | 33 | >>> use_reST("Plain string.") |
|---|
| | 34 | False |
|---|
| | 35 | >>> use_reST("Do some math: 2 * 2a* 2 = 8a") |
|---|
| | 36 | False |
|---|
| | 37 | >>> use_reST("Not*really*strong.") |
|---|
| | 38 | False |
|---|
| | 39 | >>> use_reST("Interpreted `text` is widely used as quotes, so exclude it.") |
|---|
| | 40 | False |
|---|
| | 41 | >>> use_reST("Not a :field:.") |
|---|
| | 42 | False |
|---|
| | 43 | """ |
|---|
| | 44 | def compile(pattern, user_map=None): |
|---|
| | 45 | """Compile a regex pattern using default or user mapping. |
|---|
| | 46 | """ |
|---|
| | 47 | |
|---|
| | 48 | # Word in reST can also contain hyphens and punctuation characters. |
|---|
| | 49 | mapping = {'ALPHA': r'[-.,?!\w]', 'WORD': r'[-.,?!\s\w]', |
|---|
| | 50 | 'START': r'(^|\s)', 'END': r'([.,?!\s]|$)'} |
|---|
| | 51 | |
|---|
| | 52 | if user_map: |
|---|
| | 53 | mapping = mapping.copy() |
|---|
| | 54 | mapping.update(user_map) |
|---|
| | 55 | |
|---|
| | 56 | def sub(text, mapping): |
|---|
| | 57 | for From, To in mapping.iteritems(): |
|---|
| | 58 | text = text.replace(From, To) |
|---|
| | 59 | return text |
|---|
| | 60 | |
|---|
| | 61 | return re.compile(sub(pattern, mapping), re.LOCALE | re.VERBOSE) |
|---|
| | 62 | |
|---|
| | 63 | def inline_markup(start, end=None, mapping=None): |
|---|
| | 64 | if not end: |
|---|
| | 65 | end = start |
|---|
| | 66 | return compile(r'''(START %(start)s ALPHA %(end)s END) | |
|---|
| | 67 | (START %(start)s ALPHA WORD* ALPHA %(end)s END)'''\ |
|---|
| | 68 | % {'start': start, 'end': end}, mapping) |
|---|
| | 69 | |
|---|
| | 70 | def line_markup(start, end=None): |
|---|
| | 71 | return inline_markup(start, end, mapping={'ALPHA': r'[-.,?!\s\w]', |
|---|
| | 72 | 'START': r'(\n|^)[\ \t]*', |
|---|
| | 73 | 'END': r''}) |
|---|
| | 74 | |
|---|
| | 75 | emphasis_pattern = inline_markup(r'\*') |
|---|
| | 76 | strong_pattern = inline_markup(r'\*\*') |
|---|
| | 77 | inline_pattern = inline_markup(r'``') |
|---|
| | 78 | hyperlink_pattern = inline_markup(r'\(', r'_\)', |
|---|
| | 79 | {'ALPHA': r'\w', 'WORD': r'[-.\w]'}) |
|---|
| | 80 | long_hyperlink_pattern = inline_markup(r'\(`', r'`_\)') |
|---|
| | 81 | field_pattern = line_markup(r':') |
|---|
| | 82 | bullet_pattern = line_markup(r'\*', r'') |
|---|
| | 83 | |
|---|
| | 84 | rest_patterns = [strong_pattern, |
|---|
| | 85 | emphasis_pattern, |
|---|
| | 86 | inline_pattern, |
|---|
| | 87 | hyperlink_pattern, |
|---|
| | 88 | long_hyperlink_pattern, |
|---|
| | 89 | field_pattern, |
|---|
| | 90 | bullet_pattern] |
|---|
| | 91 | |
|---|
| | 92 | for pattern in rest_patterns: |
|---|
| | 93 | if re.search(pattern, text): |
|---|
| | 94 | return True |
|---|
| | 95 | |
|---|
| | 96 | return False |
|---|
| | 97 | |
|---|
| | 98 | |
|---|