MarkdownをCosense記法に置換するUserScript
Cosense(旧称Scrapbox)で使用するUserScriptです。
更新履歴
2024-06-22:イタリックを置換する機能を無効化(置換対象に「アンダーバーを含むURL」がある場合にURLを壊すのを防ぐため)
2019-12-17:Markdownのエスケープを元に戻す機能を追加
2019-12-15:番号付きリストの置換機能を追加
2019-12-12:リストの置換機能を追加
2019-12-10:公開
置換できるもの
ここに挙げているものだけを置換できます。
強調を太字へ置換
**hoge**→[* hoge]
__hoge__→[* hoge]
取り消し線
~~hoge~~→[- hoge]
見出し(レベル1〜6)を、それぞれに対応する大きな字へ置換
# hoge→[******* hoge]
## hoge→[****** hoge]
### hoge→[***** hoge]
#### hoge→[**** hoge]
##### hoge→[*** hoge]
###### hoge→[** hoge]
ハイパーリンク
[Google](https://www.google.com)→[Google https://www.google.com]
[](https://www.google.com)→[https://www.google.com]
<https://www.google.com>→[https://www.google.com]
画像
![画像の名前](画像のURL)→[画像の名前 画像のURL]
※このように置換前のMarkdownに「画像の名前」が記入されている場合は、置換後には「画像の名前」だけがCosenseのページ上に表示され、画像そのものはリンク先で開いて見る状態になります。すなわち、画像自体はCosenseのページ上では見えません。
![](画像のURL)→[画像のURL]
※このように置換前のMarkdownに「画像の名前」が記入されていない場合は、置換後には画像自体がCosenseのページ上に表示されます。
リスト(番号なしリスト)
半角の* , + , - のいずれかで始まっている行(Markdownのリスト)を箇条書きに置換します。
置換前のMarkdownにおいて、リストのインデント(階層を1段下げること)のためには、タブ1個/半角スペース4個ずつ/半角スペース2個ずつのいずれかが使われていると思います。階層を1段下げるために〈半角スペース2個ずつ〉が使用されている場合は、それを正しく置換できるようにするために、下記のコードの一部を書き換える必要があります。詳しくは後述の節(MarkdownをCosense記法に置換するUserScript#5df17dd1027cb3000048ec57)を参照してください。
番号付きリスト
1. hogeのように〈半角数字+ドット+半角スペース1個〉で始まっている行(Markdownの数字付きリスト)は番号付きリストに置換します。
置換前のときに、番号(1. など)が行頭にある場合のみに対応しています。
水平線を水平線の画像に置換して、線を再現
半角のアスタリスク(*)、ハイフン(-)、アンダーバー(_)のいずれかが、行頭から3個以上連続している箇所(Markdownの水平線)は、水平線の画像に置き換えます。
記号のエスケープを元に戻す
Markdownでは\*_{}[]()#+-.!という14種類の記号やバッククォートを記入する際は、バックスラッシュを付けて\+などのように書きますが、これをバックスラッシュが付かない形に戻します。
なお、Markdownにおける引用(行頭に>)と、インラインコード(文字をバッククォートで囲む)は、Cosense記法においてもそれらと同じ書き方をするので、Cosenseで元通りに再現されます。
導入の仕方
こちらのヘルプに従って、にてUser Scriptを"Enabled"に変更します。
下記のコード(code:script.jsの行も含む)を、Cosenseの「自分のページ」に貼り付けてからブラウザをリロードし、ページ上部に表示される"Load new UserScript"をクリックします。それで完了です。
コード
code:script.js
scrapbox.PopupMenu.addButton({
title: 'MdSc', //"MdSc" はポップアップするボタンの名前。変更可能。
onClick: text =>{
////リスト////
//リストのマーカーが行頭にある場合
text=text.split(/\n/).map(line => line.replace(/^\*\-\+ /g,' ')).join('\n')
//行頭以外にあるリストのマーカー(*, -, +)を消す
text=text.split(/\n/).map(line => line.replace(/\*\-\+ /g,'')).join('\n')
//リストのインデントが半角スペース2個ずつの場合
//text=text.split(/\n/).map(line => line.replace(/ {2}/g,' ')).join('\n')
//リストのインデントが半角スペース4個ずつの場合
text=text.split(/\n/).map(line => line.replace(/ {4}/g,' ')).join('\n')
////数字付きリスト
text=text.split(/\n/).map(line => line.replace(/^(0-9+\. )/g,' $1')).join('\n')
////強調////
//太字
text=text.split(/\n/).map(line => line.replace(/\*{2}(^*+)\*{2}/g,'$1')).join('\n')
text=text.split(/\n/).map(line => line.replace(/\_{2}(^_+)\_{2}/g,'$1')).join('\n')
//イタリック(URLにアンダーバーを含むハイパーリンクの置換を妨害するのでコメントアウト)
//text=text.split(/\n/).map(line => line.replace(/\_(^_+)\_/g,'$1')).join('\n')
////取り消し線////
text=text.split(/\n/).map(line => line.replace(/\~\~(\~+|^~+)\~\~/g,'$1')).join('\n')
////Header level 1-6////
//Header level 1
text=text.split(/\n/).map(line => line.replace(/^# (.*)/g,'$1')).join('\n')
//Header level 2
text=text.split(/\n/).map(line => line.replace(/^#{2} (.*)/g,'$1')).join('\n')
//Header level 3
text=text.split(/\n/).map(line => line.replace(/^#{3} (.*)/g,'$1')).join('\n')
//Header level 4
text=text.split(/\n/).map(line => line.replace(/^#{4} (.*)/g,'$1')).join('\n')
//Header level 5
text=text.split(/\n/).map(line => line.replace(/^#{5} (.*)/g,'$1')).join('\n')
//Header level 6
text=text.split(/\n/).map(line => line.replace(/^#{6} (.*)/g,'$1')).join('\n')
////リンクと画像////
//Hyperlink without linktext / Image without alt text
//e.g. [](https://www.google.com) or ![](https://www.google.com/google.png)
text=text.split(/\n/).map(line => line.replace(/!?\\\((https?:\/\/\w/:%#\$&\?\(\)~\.=\+\-+)\)/g,'$1')).join('\n')
//Image with alt text
//e.g. !Google logo(https://www.google.com/google.png)
text=text.split(/\n/).map(line => line.replace(/!\[(^\]+)\]\((https?:\/\/\w/:%#\$&\?\(\)~\.=\+\-+)\)/g,'$1 $2')).join('\n')
//Hyperlink with linktext
//e.g. Google(https://www.google.com)
text=text.split(/\n/).map(line => line.replace(/\[(^\]+)\]\((https?:\/\/\w/:%#\$&\?\(\)~\.=\+\-+)\)/g,'$1 $2')).join('\n')
//URL with angle brackets
//e.g <https://www.google.com>
text=text.split(/\n/).map(line => line.replace(/<(https?:\/\/\w/:%#\$&\?\(\)~\.=\+\-+)>/g,'$1')).join('\n')
////水平線////
text=text.split(/\n/).map(line => line.replace(/^(\*|\-|\_){3,}/g,'/icons/hr.icon')).join('\n')
////エスケープを元に戻す////
text=text.split(/\n/).map(line => line.replace(/\\([\\|`|\*|_|\{|\}|\|\|\(|\)|#|\+|\-|\.|\!])/g,'$1')).join('\n')
return text;
}
})
使い方
Markdownで書かれたテキストをCosenseのページに貼り付けて、その部分をマウスなどで選択し、そこにポップアップするボタンの中にある"MdSc"をクリックすると置換されます。
https://gyazo.com/fca4d205d6acb494ee02c468b7e42e27
(Markdownを貼り付けた状態:太字/取り消し線/見出し/ハイパーリンク)
※イタリックの置換機能は現在は無効化しています。有効化する方法は後述。→MarkdownをCosense記法に置換するUserScript#67c66b7d027cb30000085879
https://gyazo.com/0c77b2aaba0baf2851625aeb140e5541
(Markdownを貼り付けた状態:画像/リスト/番号付きリスト/水平線)
https://gyazo.com/0bb4e833e0f605840abbdb7ac1678cc3
(置換したい範囲をマウス等で洗濯し、ポップアップするボタンの中の“MdSc”をクリック)
https://gyazo.com/78b69cd40eb7b7299cf0d37b35b1e55c
(置換後:太字/取り消し線/見出し/ハイパーリンク)
https://gyazo.com/a69396f7b893085a991fc7eaf9d0ecf8
(置換後:画像/リスト/番号付きリスト/水平線)
使用時の注意点(想定外の置換が起こる例)
置換対象の範囲に、Markdownのリストのインデント(階層下げ)以外の用途で、半角スペースが4個以上もしくは2個以上連続している箇所があると、Cosense記法への置換後には、その半角スペースの個数は改変されます。デフォルトでは、4個以上の連続で置換対象になります。
例:hoge fugaなど
「半角スペース4個以上もしくは2個以上の連続」は、Markdownのリストのインデント部分と同一なので、置換対象に該当してしまうためです。
半角スペースの連続する個数が4個以上で置換対象になるか、あるいは2個以上で置換対象になるかは、後述の編集内容(MarkdownをCosense記法に置換するUserScript#5df17dd6027cb3000048ec58)によって決まります。
置換対象の範囲に、Markdownにおけるコードブロック記法(行頭からタブ1個または半角スペース4個)があると、その箇所は、Cosense記法への置換後には「箇条書き」の状態へ置換されてしまいます。
「タブ1個または半角スペース4個」はリストのインデントとして置換対象に該当するためです。
置換対象の範囲に、Cosense記法の太字([* hoge])や取り消し線([- hoge])がすでに含まれている場合は、その箇所に対してこのUserScriptを適用すると、Cosense記法が壊されます。* と- の部分が「Markdownのリストのマーカー」と同一なので、置換対象に該当してしまうためです。それらを置換対象の範囲に含めないように注意してください。
リストのマーカー(* , + , - のいずれか)の直後に半角スペースがある場合は、それを箇条書きに置換した際に、階層が正しく再現されません。
再現されない例:* hoge(* の直後に半角スペースがある)
正しく再現される例:* hoge
置換対象に含まれているURLの中に、例えばhttps://sample.com/__hoge__というように「アンダーバー2個ずつ」で囲まれた部分があると、この部分は「Markdownにおける強調が施された箇所」と同じ形なので、[* hoge]という太字に置換されてしまい、URLとしては壊れてしまいます。対策は後述(→ MarkdownをCosense記法に置換するUserScript#67c66eff027cb3000008588f)のとおりです。
Markdownが入れ子になっている場合は、正しい置換結果にならないと思います。
例:~~**hoge**~~など
コードの編集
番号なしリストのインデントが〈半角スペース2個ずつ〉で行われている場合に対応させる
置換前のMarkdownにおいて、番号なしリストの階層をインデントする(1段下げる)ごとに〈半角スペース2個ずつ〉が使われている場合は、上掲のコードの中の、下記の部分の2行目の行頭にある//を取り除き、かつ4行目の行頭に//を書き加えます。
code:編集前の状態
//リストのインデントが半角スペース2個ずつの場合
//text=text.split(/\n/).map(line => line.replace(/ {2}/g,' ')).join('\n')
//リストのインデントが半角スペース4個ずつの場合
text=text.split(/\n/).map(line => line.replace(/ {4}/g,' ')).join('\n')
そのように編集したら、ブラウザをリロードし、ページ上部に表示される"Load new UserScript"をマウスでクリックします。
「アンダーバー2個ずつ」で囲まれた部分をもつURLを壊さないようにする
上掲のスクリプト内の、こちらの行の行頭に、半角で//を記入して下さい。
code:script.js
text=text.split(/\n/).map(line => line.replace(/\_{2}(^_+)\_{2}/g,'$1')).join('\n')
そのように編集したら、ブラウザをリロードし、ページ上部に表示される"Load new UserScript"をマウスでクリックします。
「アンダーバー2個ずつ」で囲まれた部分をもつURLは壊れなくなり、かつ、__hoge__という「Markdownにおける強調が施された部分」は置換されなくなります。
イタリックの置換を有効にする
イタリック(斜体)の置換を有効にしたい場合は、上掲のスクリプト内の、こちらの行の行頭にある//を消して下さい。
code:script.js
//text=text.split(/\n/).map(line => line.replace(/\_(^_+)\_/g,'$1')).join('\n')
そのように編集したら、ブラウザをリロードし、ページ上部に表示される"Load new UserScript"をマウスでクリックします。
_hoge_は[/ hoge]に置換されるようになります。これにより、URL内に_hoge_があるときはそれも置換され、URLとしては壊れるようになります。
関連記事
インポート元がWorkflowyの場合は、専用のUserScriptがあります。
WorkflowyからMarkdown形式でエクスポートした内容をCosense形式に変換するUserScript
MarkdownをCosense記法に置換する機能をもつツールは他にもあります。
/scrapboxlab/アウトライナーからScrapboxへのインポートを助けるツールの機能比較
/icons/hr.icon
#JavaScript