Textileのはなしと「What is the best regular expression to check if a string is a valid URL?」のはなし

Pygments の lexer が over 400 になった日で唐突に Textile の話を出したけれど。

現状の Pygments では「軽量マークアップ」系の lexer としては、

  • BBCode(-like)
  • MoinMoin (and Trac) Wiki markup
  • reStructuredText
  • \(\TeX\) and \(\LaTeX\)
  • (g)roff typesetting

が既に書かれている。

Markdown は当然要望があがっていて、Votes数も結構多く、MediaWikiも要望があがっていて、多少は求められているらしい。なのでこれら2つは、そのうち誰かが書くんじゃないか、とは思う。どちらも(来年4月の) 2.2 よりも後ではないかとは思うけれど。

というわけで、Creole(系)と Textile については Texinfo 同様に要望さえあがっていないんだけれども、ともにあれば喜ぶ人はいるのではないだろうか。

「プレインテキストとして読めること」に一番重きを置いている reStructuredText を除けば、これらのどれも「記述量を少なく、たくさんのインラインマークアップを提供」することも重視するため、\(\TeX\) and \(\LaTeX\) や g(roff) ほどではないにせよ、プレインテキストとして読もうとするとキツくなってくるような煩雑な記述も出来る

じゃぁ、実際にソースそのものを扱う機会の多い markdown を除いて、MediaWiki、Creole、Textile ソースが「読みにくい」ことでどれだけの誰が困るんだ、と言われれば、これはそんなには困らないであろう。この3つのいずれも、今のところほとんどが「Wiki的」なもので、WEB インターフェイスとセットで使う、つまり、編集者は「Edit」で多少の読む苦痛を感じながらも「Preview」でレンダリング結果を逐一確認しながら書くわけであるし、読者はそのソースを読むことなんかしない。であるから、仮に MediaWiki、Creole、Textile の Pygments lexer が書かれたとしたら、その主なユーザはおそらく「これらの説明をしたい人々」となるであろう。

で、Textile のはなし。

わたしこれ、ずっと名前だけ知っていて使ったことがない、と思い込んでいたが、違ってた。Redmine が使ってるので、そこで多分使ってたと思う。Redmine ユーザ歴は半年にも満たないし、その期間も真剣なユーザではなかったので、あまり憶えてないけど。

「本物の Creole1.0」の仕様が綺麗なのは書いた。MediaWiki の仕様が「アナーキー」なことも書いた。じゃあ Textile はどうか? これは「結構よく書かれている」。本家はここ。テストも良くされているようで、python-textileはテストコードのネタとしても使えるし、実際にレンダリング結果の確認もすぐに出来てありがたい。だから好印象だ。

「だから好印象だ」から「好きになれる」かって? ワタシにはちょっと中途半端な仕様に思える。typographers-quotesから続く typesetting 系のマークアップは、いっけん「こんなにあるのか、ステキ!」と思いかねないほどに大量にあるが、\(\TeX\)、 \(\LaTeX\) や (g)roff を知っていればこんなのはそれらからの「劣化版」に過ぎないし、悪く言えば「それらの悪いとこだけ受け継いだ」ようにさえみえる。Dimension signの「quotes may be applied to the dimensions to represent feet and inches.」なんぞは、一部の国、つまりは「アメリカ人にあらずば人にあらず」満載なんであって、想像つくと思うがワタシなら「ここまでしたいなら \(\TeX\) / MathJax 使おうよ」と思う。

そんなわけで「Textileユーザとして」ではありえないんだけれども、Texinfo 前の練習に、と、ちょっとずつ Textile の Pygments lexer を書き始めてるんだけれどもね。まぁちょいちょいイヤらしいのね。リンクの仕様なんだけどさ、

 1 Learn more "about the company":/about and our "board of directors":../about#board.
 2 
 3 Visit our "parent company (Example Corporation)":http://example.com.
 4 
 5 This is a link to a ["Wikipedia article about Textile":http://en.wikipedia.org/wiki/Textile_(markup_language)].
 6 
 7 I'm really excited about "RedCloth":redcloth.  I love it so much, I think I'll name my first child "RedCloth":redcloth.
 8 
 9 [redcloth]http://redcloth.org
10 
11 "(my-class). This is a link with class":http://redcloth.org

まず最初の例のは http:// などのスキーマがなくてもいいぞ、って例だよね。さらにいえば ../about#board. の末尾のピリオドは url の一部ではなく、テキスト本文の句読点。WikiPedia へのリンクの例のように、「困ったら[]で囲め」と言うんだけれども、ワタシなんぞは「だったら最初から全部これで書かせりゃいいのに」と思うのだ。だってそうじゃん。「反応しないんですけど」「[]使えばいいんだぜ」なんて FAQ を増量しなくたっていいじゃないか、なんで好き好んでトラブル増やしたいの、と。

あなたがどれだけ想像出来るかわからんが、フリーテキストの中から url (のようなもの)を見つける、というタスクは決して簡単なんかではない。最初に python-textile で見つけた正規表現で、ほかに良い手はないか、と探っていて元ネタを見つけた、というのがこんな:

 1 (?xi)
 2 \b
 3 (                           # Capture 1: entire matched URL
 4   (?:
 5     [a-z][\w-]+:                # URL protocol and colon
 6     (?:
 7       /{1,3}                        # 1-3 slashes
 8       |                             #   or
 9       [a-z0-9%]                     # Single letter or digit or '%'
10                                     # (Trying not to match e.g. "URI::Escape")
11     )
12     |                           #   or
13     www\d{0,3}[.]               # "www.", "www1.", "www2." … "www999."
14     |                           #   or
15     [a-z0-9.\-]+[.][a-z]{2,4}/  # looks like domain name followed by a slash
16   )
17   (?:                           # One or more:
18     [^\s()<>]+                      # Run of non-space, non-()<>
19     |                               #   or
20     \(([^\s()<>]+|(\([^\s()<>]+\)))*\)  # balanced parens, up to 2 levels
21   )+
22   (?:                           # End with:
23     \(([^\s()<>]+|(\([^\s()<>]+\)))*\)  # balanced parens, up to 2 levels
24     |                                   #   or
25     [^\s`!()\[\]{};:'".,<>?«»“”‘’]        # not a space or one of these punct chars
26   )
27 )

ここまでしないと例えば末尾のピリオドが url の一部でないことを判別出来ないし、この正規表現でも

1 This is a link to a ["Wikipedia article about Textile":http://en.wikipedia.org/wiki/Textile_(markup_language)].

には不十分。(http://en.wikipedia.org/wiki/Textile_(markup_language)]と「]」までを url だと思い込む。)無論このケースでは「[“Link desc”:path]」全体としてキャプチャ後の path を url として解析する必要がある

まぁこんななんで、Textile の lexer も結構時間かかると思う。ワタシのサイトの読者でこれを待つ人もいるとも思えないが、まぁ欲しいと思う人は気長に待ってくれ。












補足。BitBucket Wiki でも Redmine でも Textile 記法、使えるけれども、どちらも「フルスペック」じゃないので注意ね。












2015-11-13 02:40追記
Textile の Pygments lexer はやめることにした。詳しくはこれ参照