File Coverage

blib/lib/Regexp/Common/Markdown.pm
Criterion Covered Total %
statement 33 33 100.0
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 41 41 100.0


line stmt bran cond sub pod time code
1             ##----------------------------------------------------------------------------
2             ## Markdown Common Regular Expressions - ~/lib/Regexp/Common/Markdown.pm
3             ## Version v0.1.4
4             ## Copyright(c) 2020 DEGUEST Pte. Ltd.
5             ## Author: Jacques Deguest <@sitael.tokyo.deguest.jp>
6             ## Created 2020/08/01
7             ## Modified 2020/08/16
8             ##
9             ##----------------------------------------------------------------------------
10             package Regexp::Common::Markdown;
11             BEGIN
12             {
13 20     20   2036220 use strict;
  20         218  
  20         614  
14 20     20   115 use warnings;
  20         39  
  20         531  
15 20     20   112 use warnings::register;
  20         37  
  20         2483  
16 20     20   10671 use Regexp::Common qw( pattern );
  20         94865  
  20         86  
17 20     20   3217389 use Regexp::Common qw( URI );
  20         211  
  20         93  
18 20     20   2888 use Regexp::Common qw( Email::Address );
  20         47  
  20         97  
19             ## We use URI::tel instead of Regexp::Common::tel because its regular expression is antiquated
20             ## URI::tel uses the latest rfc3966
21 20     20   195716 use URI::tel;
  20         279612  
  20         61074  
22 20     20   119 our $VERSION = 'v0.1.4';
23              
24 20         89 our $SPACE_RE = qr/[[:blank:]\h]/;
25             ## Including vertical space like new lines
26 20         61 our $SPACE_EXTENDED_RE = qr/[[:blank:]\h\v]/;
27 20         3632 our $ATTRIBUTE_RE = qr/
28             [\w\-]+
29             $SPACE_EXTENDED_RE*
30             =
31             $SPACE_EXTENDED_RE*
32             (?:
33             \"[^\"]+\" # attribute="value"
34             |
35             \'[^\']+\' # attribute='value'
36             |
37             \S+ # attribute=value
38             )
39             $SPACE_EXTENDED_RE*
40             /x;
41 20         119 our $LIST_TYPE_ORDERED = qr/(?\d+[\.])/;
42            
43 20         70 our $LIST_TYPE_UNORDERED_MINUS = qr/
44             (?
45             [\-]
46             (?!
47             (?:
48             [ ]?[\-][ ]?
49             ){2,}
50             )
51             )
52             /x;
53            
54 20         68 our $LIST_TYPE_UNORDERED_PLUS = qr/(?[\+])/;
55            
56 20         55 our $LIST_TYPE_UNORDERED_STAR = qr/
57             (?
58             [\*]
59             (?! # Make sure not to catch horizontal lines marked with stars
60             (?:
61             [ ]?[\*][ ]?
62             ){2,}
63             )
64             )
65             /x;
66            
67 20         1050 our $LIST_TYPE_UNORDERED = qr/
68             $LIST_TYPE_UNORDERED_STAR
69             |
70             $LIST_TYPE_UNORDERED_MINUS
71             |
72             $LIST_TYPE_UNORDERED_PLUS
73             /x;
74            
75             ## Taken from Markdown original author, John Gruber's original regular expression
76             ## See to see it in action
77 20         2401 our $LIST_ALL = qr/
78             (?:(?<=\n\n)|\A\n*|\n{2,})
79             (? # whole list
80             (? # list prefix and type
81             [\s]{0,3}
82             (? # Any of posible list prefix, but that aviod atching also horizontal rules
83             (?:
84             (?(?&list_unordered_star))
85             |
86             (?(?&list_unordered_minus))
87             |
88             (?(?&list_unordered_plus))
89             |
90             (?(?&list_ordered))
91             )
92             )
93             [ \t]+
94             )
95             (?(?s:.+?)) # list content
96             (?
97             \z
98             |
99             \n{2,}
100             (?=\S)
101             (?! # Negative lookahead for another list item marker
102             [ \t]*
103             (?
104             (?:
105             (?(?&list_unordered_star))
106             |
107             (?(?&list_unordered_minus))
108             |
109             (?(?&list_unordered_plus))
110             |
111             (?(?&list_ordered))
112             )
113             )
114             [ \t]+
115             )
116             )
117             )
118             (?(DEFINE) # Definition block for recursive pattern matching
119             $LIST_TYPE_UNORDERED_STAR
120             $LIST_TYPE_UNORDERED_MINUS
121             $LIST_TYPE_UNORDERED_PLUS
122             $LIST_TYPE_ORDERED
123             )
124             /mx;
125              
126 20         1815 our $REGEXP =
127             {
128             ## Bold
129             ## https://regex101.com/r/Jp2Kos/2/tests
130             bold => qr/
131             (?
132             (?
133             (?\*{2}|\_{2}) # Emphasis type: * or _
134             (?=\S) # followed by non-space
135             (?.+?[*_]*) # enclosed text
136             (?<=\S) # making sure preceding stuff was a non-space
137             \g{bold_type} # Balanced closing tag
138             )
139             /x,
140            
141             ## Code borrowed from original Markdown author: John Gruber
142             ## https://regex101.com/r/TdKq0K/1
143             bquote => qr/
144             (? # Wrap whole match in $1
145             (
146             ^[ \t]*>[ \t]? # '>' at the start of a line
147             .+\n # rest of the first line
148             (?.+\n)* # subsequent consecutive lines
149             \n* # blanks
150             )+
151             )
152             /xm,
153            
154             ## ```
155             ## Some code
156             ## ```
157             code_block => qr/
158             (?:\n+|\A)? # Necessarily at the begining of a new line or start of string
159             (?
160             (?
161             [ ]{0,3} # Possibly up to 3 leading spaces
162             \`{3,} # 3 code marks (backticks) or more
163             )
164             \n+
165             (?.*?) # enclosed content
166             \n+
167             (?
168             \g{code_start} # balanced closing block marks
169             (?!`)
170             [ \t]* # possibly followed by some space
171             \n
172             )
173             (?\n|\Z) # and a new line or end of string
174             /xms,
175            
176             ## Marked by left hand indentation
177             ## https://regex101.com/r/toEboU/2/tests
178             code_line => qr/
179             (?:\n{2,}|\A) # Starting at beginning of string or with 2 new lines
180             (?
181             (?:
182             (? # Lines must start with a tab or a tab-width of spaces
183             [ ]{4}
184             |
185             \t
186             )
187             (?.*\n+) # with some content, possibly nothing followed by a new line
188             )+
189             )
190             (?
191             (?=^[ ]{0,4}\S) # Lookahead for non-space at line-start
192             |
193             \Z # or end of doc
194             )
195             /xm,
196            
197             ## \x{0060} is ` in unicode; see perl -le 'printf "\\x%x", ord( "`" )'
198             code_span => qr/
199             (?
200             (?
201             (?\`{1,}) # One or more backtick(s)
202             (?.+?) # Code content inbetween back sticks
203             (?
204             \g{code_start} # Balanced closing backtick(s)
205             (?!`) # And not followed by a backtick
206             )
207             /x,
208            
209             ## https://regex101.com/r/eDb6RN/3/tests
210             em => qr/
211             (?
212             (?
213             (?\*|\_) # Emphasis type: * or _
214             (?=\S) # followed by non-space
215             (?.+?) # enclosed text
216             (?<=\S) # making sure preceding stuff was a non-space
217             (?
218             \g{em_type} # Balanced closing tag
219             )
220             /x,
221            
222             ## Headers: #, ##, ###, ####, #####, ###### become h1..6
223             # atx-style headers:
224             # # Header 1
225             # ## Header 2
226             # ## Header 2 with closing hashes ##
227             # ...
228             # ###### Header 6
229             ## https://regex101.com/r/9uQwBk/2/tests
230             header => qr/
231             (?
232             (?
233             (?\#+) # one or more #
234             [ \t]* # Possibly followed by some spaces or tabs
235             (?.+?) # Header content enclosed
236             [ \t]* # Possibly followed by some spaces or tabs
237             \g{header_level}* # Possibly with closing balanced #
238             \n+ # Terminated by a new line
239             )
240             /mx,
241            
242             # Setext-style headers:
243             # Header 1
244             # ========
245             #
246             # Header 2
247             # --------
248             #
249             ## This is to be on a single line of its own
250             ## https://regex101.com/r/sQLEqz/2
251             header_line => qr/
252             (?
253             (?.+) # Header content
254             [ \t]* # Possibly followed by spaces or tabs
255             \n # With then a new line
256             (?
257             (?[\=|\-]+) # Multiple = or -
258             [ \t]* # Possibly followed by spaces or tabs
259             \n+ # Terminated by a new line
260             )
261             /mx,
262            
263             ## https://regex101.com/r/SH8ki3/2/tests
264             html => qr/
265             (?:(?<=\n\n)|\A\n*|\n{2,})
266             [ ]{0,3} # up to 3 leading space
267             (?
268             (?:
269             (?:
270             < # start of the html block withuot space before
271             [[:blank:]\h\v]*
272             (?[a-zA-Z0-9][\w\-]+) # tag name starting with alphanumeric character
273             (?(?&tag_attr))*
274             [[:blank:]\h\v]*
275             >
276             (?.*?)
277             (? # balanced closing tag
278             <
279             [[:blank:]\h\v]*
280             \/
281             \g{tag_name}
282             [[:blank:]\h\v]*
283             >
284             )
285             )
286             | # or
287             (?:
288             # html comment
289             )
290             | # or
291             (?:
292             < # standalone tag
293             [[:blank:]\h\v]*
294             (?[a-zA-Z0-9][\w\-]+)
295             (?(?&tag_attr))*
296             [[:blank:]\h\v]*
297             \/?
298             [[:blank:]\h\v]*
299             >
300             )
301             )
302             (? # making sure what follows is
303             \z # either end of string
304             | # or
305             [ ]*\n{1,2}
306             (?! # not html data
307             [[:blank:]\h\v]*
308             (?:
309             (?:
310             <
311             [[:blank:]\h\v]*
312             [a-zA-Z0-9][\w\-]+
313             (?:(?&tag_attr))*
314             [[:blank:]\h\v]*
315             >
316             )
317             |
318             (?:
319             <
320             [[:blank:]\h\v]*
321             \/?
322             [[:blank:]\h\v]*
323             [\w\-]+
324             (?:(?&tag_attr))*
325             [[:blank:]\h\v]*
326             \/?
327             [[:blank:]\h\v]*
328             >
329             )
330             )
331             )
332             )
333             )
334             (?(DEFINE)
335             (?
336             (?:
337             [[:blank:]\h]*
338             [\w\-]+
339             [[:blank:]\h]*
340             =
341             [^\"\'[:blank:]\h]+
342             [[:blank:]\h]*
343             )
344             |
345             (?:
346             [[:blank:]\h]*
347             [\w\-]+
348             [[:blank:]\h]*
349             =
350             [[:blank:]\h]*
351             (?["'])
352             (.*?)
353             \g{quote}
354             [[:blank:]\h]*
355             )
356             )
357             )
358             /xsm,
359            
360             ## Basically same as link, except there is an exclamation mark (!) just before:
361             ## Ex: ![alt text](url "optional title")
362             ## https://regex101.com/r/z0yH2F/5/tests
363             img => qr/
364             (?
365             (?
366             \!\[(?.+?)\] # image alternative text, i.e. the text used when the image does not
367             (?:
368             (?:
369             [ ]? # possibly followed by some spaces
370             (?:\n[ ]*)? # and a new line with some space
371             \[(?.*?)\] # with the link id in brackets, but may be empty
372             )
373             |
374             (?:
375             \(
376             [ \t]*
377             (?:
378             <(?.*?)> # link url within <>; or
379             |
380             (?.*?) # link url without <>
381             )
382             [ \t]* # possibly followed by some spaces or tabs
383             (?:
384             (?['"]) # Title is surrounded ether by double or single quotes
385             (?.*?) # actual title, but could be empty as in ""
386             \g{img_title_container} # make the sure enclosing mark balance
387             )?
388             \)
389             )
390             )
391             )
392             /xm,
393            
394             # ^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$
395             ## Horizontal line
396             ## https://daringfireball.net/projects/markdown/syntax#hr
397             ## https://regex101.com/r/Vlew4X/2
398             line => qr/
399             ^ # At start of line
400             $SPACE_RE{0,2} # with up to 3 spaces before
401             (?
402             (?
403             $SPACE_RE?
404             (?\*|\-|\_) # asterisk, hyphen or underscore
405             $SPACE_RE? # possibly followed by spaces
406             ){3,} # 3 or more occurences
407             [ \t]*
408             $ # end of line or end of string
409             /mx,
410            
411             ## https://regex101.com/r/6VG46H/1
412             line_break => qr/
413             (?
414             [ ]{2,}\n
415             )
416             /mx,
417            
418             ## Link
419             ## https://daringfireball.net/projects/markdown/syntax#link
420             ## https://regex101.com/r/sGsOIv/4
421             ## Links' id can be multiline, so we need the /s modifier
422             link => qr/
423             (? # Check it was not escaped with a \
424             (?
425             (?
426             (?>\\[\[\]]|[^\[\]])*+ # Link text
427             )
428             (?
429             (?:
430             (?:
431             [ ]? # possibly followed by some spaces
432             (?:\n[ ]*)? # and a new line with some space
433             (?.*?)(?
434             )
435             |
436             (?:
437             (?
438             [ \t]*
439             (?:
440             <(?.*?)> # link url within <>; or
441             |
442             (?.*?) # link url without <>
443             )
444             [ \t]* # possibly followed by some spaces or tabs
445             (?:
446             (?['"]) # Title is surrounded ether by double or single quotes
447             (?.*?) # actual title, but could be empty as in ""
448             \g{link_title_container} # make sure the enclosing mark balance
449             )?
450             (?
451             (?![[:blank:]\h]+["'][^"']+["'])
452             )
453             )
454             )
455             /xms,
456            
457             ## https://regex101.com/r/bAUu1E/4/tests
458             link_auto => qr/
459             (?
460             (?
461             <
462             (?
463             (?$RE{URI}{HTTP}) # http
464             |
465             (?$RE{URI}{HTTP}{-scheme => 'https'}) # https
466             |
467             (?$RE{URI}{FTP}) # ftp
468             |
469             (?$URI::tel::TEL_URI) # tel
470             |
471             (?$RE{URI}{file}) # file
472             |
473             (?$RE{URI}{news}) # news
474             |
475             (?(?:mailto\:)?$RE{Email}{Address}) # email address: mailto:john@example.com or simply john@example.com
476             )
477             >
478             )
479             /x,
480            
481             ## Definition
482             ## https://daringfireball.net/projects/markdown/syntax#link
483             ## https://regex101.com/r/edg2F7/2/tests
484             link_def => qr/
485             ^[ ]{0,3} # Leading space up to 3
486             (?
487             (?.+?)(?
488             [ \t]* # Possibly with some space before colon
489             \:
490             [ \t]*\n?[ \t]* # Possibly with some space after the colon, possibly with a new line in between?
491             (?:
492             <(?[^\>]+)> # link within <>
493             |
494             (?\S+) # or link without <>
495             )
496             (?:
497             (?:
498             [ \t]+ # Either some space or tabs
499             |
500             [ \t]*\n[ \t]* # or a new line surrounded by 0 or more spaces or tabs
501             )
502             (?:
503             (?:
504             (?['"]) # Title is surrounded ether by double or single quotes
505             (?.+?)
506             \g{link_title_container} # make the sure enclosing mark balance
507             )
508             | # or
509             \((?[^\)]+)\) # by parenthesis
510             )
511             )?
512             [ \t]* # Possibly ending with some trailing spaces or tab
513             )
514             (?:\n+|\Z) # terminated by a new line or end of file
515             /xm,
516            
517             ## Link with reference to link definition id
518             ## https://daringfireball.net/projects/markdown/syntax#link
519             ## https://regex101.com/r/QmyfnH/1/tests
520             ## The /s switch is required for link name spawning multiple lines: [Some\nlink][]
521             link_ref => qr/
522             (?
523             (?.+?)(?
524             [ ]? # possibly followed by some spaces
525             (?:\n[ ]*)? # and a new line with some space
526             (?.*?)(?
527             )
528             /xms,
529            
530             ## regular expression for list, ordered or unordered
531             list_type_ordered => $LIST_TYPE_ORDERED,
532            
533             list_type_unordered => $LIST_TYPE_UNORDERED,
534            
535             ## Taken from Markdown original author, John Gruber's original regular expression
536             list => $LIST_ALL,
537            
538             ## https://regex101.com/r/RfhRVg/3
539             list_first_level => qr/
540             (?:(?<=\n\n)|\A\n*|\n{2,})
541             $LIST_ALL
542             /mx,
543            
544             list_nth_level => qr/
545             ^
546             $LIST_ALL
547             /mx,
548            
549             ## Minor deviation from John Gruber's original regular expression
550             ## Changed [ \t]+ to [ \t]* and .+? to .*? so that it catches empty list item, like:
551             ## *
552             ## * Something
553             ## https://regex101.com/r/bulBCP/1/tests
554             list_item => qr/
555             (?
556             (?\n)? # leading line
557             (?^[ \t]*) # leading whitespace
558             (? # list marker
559             (?:
560             (?:
561             (?(?&list_unordered_star))
562             |
563             (?(?&list_unordered_minus))
564             |
565             (?(?&list_unordered_plus))
566             )
567             |
568             (?(?&list_ordered))
569             )
570             )
571             [ \t]*
572             (?(?s:.*?) # list item text
573             (\n{1,2}))
574             (?= \n*
575             (
576             \z
577             |
578             \g{li_lead_space}
579             (?
580             (?:
581             (?:
582             (?(?&list_unordered_star))
583             |
584             (?(?&list_unordered_minus))
585             |
586             (?(?&list_unordered_plus))
587             )
588             |
589             (?(?&list_ordered))
590             )
591             )
592             [ \t]*
593             )
594             )
595             )
596             (?(DEFINE) # Definition block for recursive pattern matching
597             $LIST_TYPE_UNORDERED_STAR
598             $LIST_TYPE_UNORDERED_MINUS
599             $LIST_TYPE_UNORDERED_PLUS
600             $LIST_TYPE_ORDERED
601             )
602             /xm,
603            
604             ## https://regexr.com/5929n
605             ## https://regex101.com/r/0B3gR4/3
606             paragraph => qr/
607             (?
608             (?:\n{2,}|^) # Needs 1 or more new lines or start of string
609             (?[ ]{0,3}) # Possibly some leading spaces, but less than a tab worth
610             (?
611             (?:
612             (?! # some line content not starting with those exceptions
613             [[:blank:]\h]{0,3}
614             (?:
615             \*{1}[ \t]+ # a list
616             |
617             (?:\*(?:[ ]\*){2,}) # a horizontal line
618             |
619             [>+-=\#]
620             |
621             \d+\. # ordered list
622             |
623             \`{3,} # code block
624             )
625             )
626             )
627             .+
628             (?!\n(?:[=-]+))
629             (?:\n|$)
630             )+
631             )
632             /mx
633             };
634            
635             ## Extended regular expression
636 20         91099 our $REGEXP_EXT =
637             {
638             ## Ex: *[HTML]: Hyper Text Markup Language
639             ## This is similar, but different from definitions
640             ## https://regex101.com/r/ztM2Pw/2/tests
641             ex_abbr => qr/
642             (?
643             (?
644             (?.+?)(?
645             [[:blank:]\h]*
646             \:
647             [[:blank:]\h]+
648             (?.*?)
649             (?:\n|\z)
650             )
651             /x,
652            
653             ## This is same as the regular code block, except this allows for a code class or a code definition with class, id, etc.
654             ## https://regex101.com/r/Y9lPAz/2
655             ex_code_block => qr/
656             (?:\n+|\A)? # Necessarily at the begining of a new line or start of string
657             (?
658             (?
659             [ ]{0,3} # Possibly up to 3 leading spaces
660             (?:
661             (?[`]{3,}) # 3 code marks (backticks) or more
662             |
663             (?[~]{3,}) # or 3 code marks (tilde) or more
664             )
665             )
666             [ \t]*
667             (?:
668             (?:
669             (?(?&_code_class))
670             (?:
671             [ \t]*
672             \{[[:blank:]\h]*(?(?&_code_attr))[[:blank:]\h]*\}
673             )?
674             )
675             |
676             (?:
677             \{[[:blank:]\h]*(?(?&_code_attr))[[:blank:]\h]*\}
678             )
679             )?
680             \n+
681             (?.*?) # enclosed content
682             \n+
683             (?()
684             (?:
685             (?
686             \g{code_start} # balanced closing block marks
687             (?!\`)
688             )
689             |
690             (?:
691             (?
692             \g{code_start} # balanced closing block marks
693             (?!\~)
694             )
695             )
696             [ \t]* # possibly followed by some space
697             (?:\n?|\Z) # contrary to the vanilla version, we allow for no double line-break
698             )
699             (?\n|\Z) # and a new line or end of string
700             (?(DEFINE)
701             (?<_code_class> [\w\-\.]+)
702             (?<_code_attr> [^\}]+)
703             )
704             /xms,
705            
706             ## https://regex101.com/r/WuB1FR/2/
707             ex_footnote => qr/
708             (?
709             ^[ ]{0,3}
710             \[\^(?.+?)\][ ]?: # footnote id
711             [ ]*
712             \n? # maybe *one* newline
713             (? # footnote text (no blank lines allowed)
714             (?:
715             .+ # actual text
716             |
717             \n # newlines but
718             (?!\[.+?\][ ]?:\s) # negative lookahead for footnote or link definition marker.
719             (?!\n+[ ]{0,3}\S) # ensure line is not blank and followed
720             # by non-indented content
721             )*
722             )
723             )
724             /xm,
725            
726             ## https://regex101.com/r/3eO7rJ/1/
727             ex_footnote_ref => qr/
728             (? # 3 possible patterns
729             (?:
730             \[\^(?.*?)\] # extended patterns with possibly null id
731             [[:blank:]\h]* # possibly some spaces
732             \((?.+?)\) # and some text in parenthesis
733             )
734             |
735             (?:
736             \[\^(?.+?)\] # regular footnote with a mandatory id
737             (?![[:blank:]\h]*\((?:.+?)\)) # but not followed by enclosing parenthesis
738             )
739             |
740             (?:
741             \^\[(?.+?)\] # inline footnote with auto-generated id à la pandoc
742             )
743             )
744             /xms,
745            
746             # atx-style headers:
747             # # Header 1
748             # ## Header 2
749             # ## Header 2 with closing hashes ##
750             # ...
751             # ###### Header 6
752             ## ## Le Site ## {.main .shine #the-site lang=fr}
753             ## Same as regular header + parameters insides curly braces in between
754             ## https://regex101.com/r/GyzbR2/1/tests
755             ex_header => qr/
756             (?
757             (?
758             (?\#+) # one or more #
759             [ \t]* # Possibly followed by some spaces or tabs
760             (?.+?) # Header content enclosed
761             [ \t]* # Possibly followed by some spaces or tabs
762             \g{header_level}* # Possibly with closing balanced #
763             (?
764             \{
765             $SPACE_RE* # Possibly with some spaces
766             (?[^\}]*) # and attributes instead braces
767             \}
768             \n+ # Terminated by a new line
769             )
770             /xm,
771            
772             # Setext-style headers:
773             # Header 1 {.main .shine #the-site lang=fr}
774             # ========
775             #
776             # Header 2 {.main .shine #the-site lang=fr}
777             # --------
778             #
779             ## This is to be on a single line of its own
780             ## https://regex101.com/r/berfAR/2/tests
781             ex_header_line => qr/
782             (?
783             (?.+) # Header content
784             [ \t]*
785             (?
786             \{
787             [[:blank:]\h]* # Possibly with some spaces
788             (?.+?) # and attributes instead braces
789             [[:blank:]\h]*
790             \}
791             [ \t]* # Possibly followed by spaces or tabs
792             \n # With then a new line
793             (?
794             (?[\=|\-]+) # Multiple = or -
795             [ \t]* # Possibly followed by spaces or tabs
796             \n+ # Terminated by a new line
797             )
798             /mx,
799            
800             ## https://regex101.com/r/xetHV1/2
801             ex_img => qr/
802             (?
803             (?
804             \!\[(?.+?)\] # image alternative text, i.e. the text used when the image does not
805             (?:
806             (?:
807             [ ]? # possibly followed by some spaces
808             (?:\n[ ]*)? # and a new line with some space
809             \[(?.*?)\] # with the link id in brackets, but may be empty
810             )
811             |
812             (?:
813             \(
814             [ \t]*
815             (?:
816             <(?.*?)> # link url within <>; or
817             |
818             (?.*?) # link url without <>
819             )
820             [ \t]* # possibly followed by some spaces or tabs
821             (?:
822             (?['"]) # Title is surrounded ether by double or single quotes
823             (?.*?) # actual title, but could be empty as in ""
824             \g{img_title_container} # make the sure enclosing mark balance
825             )?
826             \)
827             )
828             )
829             [ \t]*
830             (?
831             \{
832             [[:blank:]\h]*
833             (?.+?)
834             [[:blank:]\h]*
835             \}
836             )
837             /x,
838            
839             # [Hyperlinked text](http://www.example.com)
840             # [Hyperlinked text](http://www.example.com "Example Site")
841             ## https://regex101.com/r/7mLssJ/2
842             ex_link => qr/
843             (?
844             (?.+?)(?
845             (?:
846             (?:
847             [ ]?
848             (?:\n[ ]*)?
849             (?.*?)(?
850             )
851             |
852             (?:
853             (?
854             [ \t]*
855             (?:
856             <(?.*?)>
857             |
858             (?.*?)
859             )
860             [ \t]*
861             (?:
862             (?['"])
863             (?.*?)
864             \g{link_title_container}
865             )?
866             (?
867             (?![[:blank:]\h]+["'][^"']+["'])
868             )
869             )
870             [ \t]*
871             (?
872             \{
873             [[:blank:]\h]*
874             (?.+?)
875             [[:blank:]\h]*
876             \}
877             )
878             /x,
879            
880             ## https://regex101.com/r/hVfXCe/2/
881             ex_link_def => qr/
882             ^[ ]{0,3} # Leading space up to 3
883             (?
884             (?.+?)(?
885             [ \t]* # Possibly with some space before colon
886             \:
887             [ \t]*\n?[ \t]* # Possibly with some space after the colon, possibly with a new line in between?
888             (?:
889             <(?[^\>]+)> # link within <>
890             |
891             (?\S+) # or link without <>
892             )
893             (?:
894             (?:
895             [ \t]+ # Either some space or tabs
896             |
897             [ \t]*\n[ \t]* # or a new line surrounded by 0 or more spaces or tabs
898             )
899             (?:
900             (?:
901             (?['"]) # Title is surrounded ether by double or single quotes
902             (?.+?)
903             \g{link_title_container} # make the sure enclosing mark balance
904             )
905             | # or
906             \((?[^\)]+)\) # by parenthesis
907             )
908             )?
909             [ \t]*
910             (?
911             \{
912             [[:blank:]\h]*
913             (?.+?)
914             [[:blank:]\h]*
915             \}
916             [ \t]* # Possibly ending with some trailing spaces or tab
917             )
918             (?:\n+|\Z) # terminated by a new line or end of file
919             /xm,
920            
921             ## Ex: {#id1} or {.cl} or {#id.cl.class}
922             md_attributes1 => qr/(?[^\}]*)\}/,
923            
924             ## https://regex101.com/r/gF6wVe/1/tests
925             ex_subscript => qr/
926             (?
927             (?:
928             (?
929             (?
930             (?>\\[\~[:blank:]\h]|[^\~[:blank:]\h\v])*+
931             )
932             (?
933             )
934             |
935             (?: # or the Microsoft way. Beurk
936             \
937             (?
938             ((?!\v).)+
939             )
940             \<\/sub\>
941             )
942             )
943             /x,
944            
945             ## https://regex101.com/r/yAcNcX/1/tests
946             ex_superscript => qr/
947             (?
948             (?:
949             (?
950             (?
951             (?>\\[\^[:blank:]\h]|[^\^[:blank:]\h\v])*+
952             )
953             (?
954             )
955             |
956             (?: # or the Microsoft way. Beurk
957             \
958             (?
959             ((?!\v).)+
960             )
961             \<\/sup\>
962             )
963             )
964             /x,
965            
966             ## https://regex101.com/r/01XCqB/9/tests
967             ex_table => qr/
968             (?:\n{2,}|\A)
969             (?
970             (?(?&t_caption))? # maybe some caption at the top?
971             (?
972             (? # Table header
973             (?(?&t_th_sep))? # Possible top separator line
974             (? # First header row
975             [^\n]+\n
976             )
977             (?(?&t_th_sep)) # a separator
978             (? # and possibly a second row of header
979             [^\n]+\n
980             (?(?&t_th_sep))
981             )?
982             )
983             )
984             (? # Multiple table rows
985             (?(?&t_row))*
986             )
987             (?(?&t_th_sep))? # Possibly ended by a separator line
988             (?(?&t_caption))? # and maybe with some caption at the bottom
989             (?
990             \z
991             |
992             \n{1,2}
993             (?!
994             (?(?&t_row))
995             )
996             )
997             )
998              
999             (?(DEFINE)
1000             (?
1001             [\+\-\|](?:[\: ]*\-+[\: ]*[\+\-\|]?)+\n
1002             )
1003             (?
1004             [ ]{0,3}
1005             (?!(?&t_th_sep)|(?&t_caption))
1006             (?:
1007             (?[\|\:]+)?
1008             (?[^\|\:\n]+)
1009             (?:
1010             (?:[\|\:]{0,2}[ ]*(?=\n))
1011             |
1012             [\|\:]{1,2}
1013             )
1014             )+
1015             (?:
1016             (?:\n(?=(?&t_th_sep)))
1017             |
1018             (?:\n(?=(?&t_caption)))
1019             |
1020             \n{1,2}
1021             )
1022             )
1023             (?
1024             [ ]{0,3}
1025             \[[^\]]+\]
1026             [ ]*
1027             \n
1028             )
1029             )
1030             /xms,
1031             },
1032             };
1033              
1034             pattern name => [qw( Markdown -extended=1 ) ],
1035             create => sub
1036             {
1037             my( $self, $flags ) = @_;
1038             my %re = %$REGEXP;
1039             ## Override vanilla regular expressions by the extended ones
1040             if( $flags->{'-extended'} )
1041             {
1042             my @k = keys( %$REGEXP_EXT );
1043             @re{ @k } = @$REGEXP_EXT{ @k };
1044             }
1045             my $pat = join( '|' => values( %re ) );
1046             return( "(?k:$pat)" );
1047             };
1048              
1049             pattern name => [qw( Markdown Bold ) ],
1050             create => $REGEXP->{bold};
1051              
1052             pattern name => [qw( Markdown Blockquote ) ],
1053             create => $REGEXP->{bquote};
1054              
1055             pattern name => [qw( Markdown CodeBlock ) ],
1056             create => $REGEXP->{code_block};
1057              
1058             pattern name => [qw( Markdown CodeLine ) ],
1059             create => $REGEXP->{code_line };
1060              
1061             pattern name => [qw( Markdown CodeSpan ) ],
1062             create => $REGEXP->{code_span};
1063              
1064             pattern name => [qw( Markdown Em ) ],
1065             create => $REGEXP->{em};
1066              
1067             pattern name => [qw( Markdown Header ) ],
1068             create => $REGEXP->{header};
1069              
1070             pattern name => [qw( Markdown HeaderLine ) ],
1071             create => $REGEXP->{header_line};
1072              
1073             pattern name => [qw( Markdown Html ) ],
1074             create => $REGEXP->{html};
1075              
1076             pattern name => [qw( Markdown Image ) ],
1077             create => $REGEXP->{img};
1078              
1079             pattern name => [qw( Markdown Line ) ],
1080             create => $REGEXP->{line};
1081              
1082             pattern name => [qw( Markdown LineBreak ) ],
1083             create => $REGEXP->{line_break};
1084              
1085             pattern name => [qw( Markdown Link ) ],
1086             create => $REGEXP->{link};
1087              
1088             pattern name => [qw( Markdown LinkAuto ) ],
1089             create => $REGEXP->{link_auto};
1090              
1091             pattern name => [qw( Markdown LinkDefinition ) ],
1092             create => $REGEXP->{link_def};
1093              
1094             pattern name => [qw( Markdown LinkRef ) ],
1095             create => $REGEXP->{link_ref};
1096              
1097             pattern name => [qw( Markdown List ) ],
1098             create => $REGEXP->{list};
1099              
1100             pattern name => [qw( Markdown ListFirstLevel ) ],
1101             create => $REGEXP->{list_first_level};
1102              
1103             pattern name => [qw( Markdown ListNthLevel ) ],
1104             create => $REGEXP->{list_nth_level};
1105              
1106             pattern name => [qw( Markdown ListItem ) ],
1107             create => $REGEXP->{list_item};
1108              
1109             pattern name => [qw( Markdown Paragraph ) ],
1110             create => $REGEXP->{paragraph};
1111              
1112             pattern name => [qw( Markdown ExtAbbr ) ],
1113             create => $REGEXP_EXT->{ex_abbr};
1114              
1115             pattern name => [qw( Markdown ExtAttributes ) ],
1116             create => $REGEXP_EXT->{md_attributes1};
1117              
1118             pattern name => [qw( Markdown ExtCodeBlock ) ],
1119             create => $REGEXP_EXT->{ex_code_block};
1120              
1121             pattern name => [qw( Markdown ExtFootnote ) ],
1122             create => $REGEXP_EXT->{ex_footnote};
1123              
1124             pattern name => [qw( Markdown ExtFootnoteReference ) ],
1125             create => $REGEXP_EXT->{ex_footnote_ref};
1126              
1127             pattern name => [qw( Markdown ExtHeader ) ],
1128             create => $REGEXP_EXT->{ex_header};
1129              
1130             pattern name => [qw( Markdown ExtHeaderLine ) ],
1131             create => $REGEXP_EXT->{ex_header_line};
1132            
1133             pattern name => [qw( Markdown ExtImage )],
1134             create => $REGEXP_EXT->{ex_img};
1135              
1136             pattern name => [qw( Markdown ExtLink ) ],
1137             create => $REGEXP_EXT->{ex_link};
1138              
1139             pattern name => [qw( Markdown ExtLinkDefinition ) ],
1140             create => $REGEXP_EXT->{ex_link_def};
1141              
1142             pattern name => [qw( Markdown ExtSubscript ) ],
1143             create => $REGEXP_EXT->{ex_subscript};
1144              
1145             pattern name => [qw( Markdown ExtSuperscript ) ],
1146             create => $REGEXP_EXT->{ex_superscript};
1147              
1148             pattern name => [qw( Markdown ExtTable ) ],
1149             create => $REGEXP_EXT->{ex_table};
1150              
1151             1;
1152              
1153             __END__