正しいURL構文かどうかをチェックするものではなく、文章中にURLが含まれるかどうかを調べるための正規表現について。
URL正規表現
ユーザーが投稿する文章にURL的文字列が含まれているかどうかチェックし、含まれていればSafe Browsing APIなどに投げたりするのに使う。
(?:[A-Za-z]{3,9})(?::\/\/|@)(?:(?:[A-Za-z0-9\-.]+[.:])|(?:www\.|[-;:&=+$,\w]+@))(?:[A-Za-z0-9.-]+)(?:[/\-+=&;%@.\w_~()]*)(?:[.!/\\\w-?%#~&=+()]*)
?:
(non-capturing group)を削除すればマッチ部分の文字列を得ることができたりもする。
マッチした文字列を得る場合
([A-Za-z]{3,9})(?::\/\/|@)((?:[A-Za-z0-9\-.]+[.:])|(?:www\.|[-;:&=+$,\w]+@))([A-Za-z0-9.-]+)([/\-+=&;%@.\w_~()]*)([.!/\\\w-?%#~&=+()]*)
URLhttps://firebase.google.com/docs/reference/js/firebase.firestore.Query#on-snapshot
に対するマッチ結果:
- https
- firebase.google.
- com
- /docs/reference/js/firebase.firestore.Query
- #on-snapshot
The Perfect URL Regular Expression の正規表現を改変した。
主な改変内容:
- ポート番号に対応
- x-www-form-url符号化形式に対応
- ドメイン不在に反応しない
- javascript:に反応しない
以下はチェック用に使ったURL
<pre class="wp-block-syntaxhighlighter-code">http://testsafebrowsing.appspot.com/s/malware.html
https://testsafebrowsing.appspot.com/
mongodb://localhost:27017/db
git@github.com:axios/axios.git
https://.com
/path/to/hoge.html
javascript:alert(1)
http://123.102.216.70:8080/view/dev/job/dev-build/
https://getbootstrap.com/docs/4.4/components/tooltips/
https://firebase.google.com/docs/reference/js/firebase.firestore.Query#on-snapshot
https://imt.services.isca.jp/imart/collaboration/schedule/user/calendar/groupweek?
https://console.firebase.google.com/u/0/project/foo-bar-112345/database/firestore/data~2Fpoints~2FHN8IjOreJYOYpaSMuGDxFEY9gAC3~2Fhistory_point_gain~2F0GWxXldAJrwjWOMYjh0M
https://www.boost.org/doc/libs/1_66_0/libs/regex/doc/html/boost_regex/ref/non_std_strings/mfc_strings/mfc_intro.html
https://ja.nuxtjs.org/guide/routing#%E3%83%8D%E3%82%B9%E3%83%88%E3%81%95%E3%82%8C%E3%81%9F%E3%83%AB%E3%83%BC%E3%83%88
http://localhost:9000/?path=/story/foo-bar--default
https://vue-test-utils.vuejs.org/ja/api/wrapper/#setdata-data
https://kamigame.jp/%E9%99%B0%E9%99%BD%E5%B8%AB/index.html
https://ja.wikipedia.org/wiki/%E9%99%B0%E9%99%BD%E5%B8%AB_(%E3%82%B2%E3%83%BC%E3%83%A0)
https://ja.wikipedia.org/wiki/%E9%99%B0%E9%99%BD%E5%B8%AB_(%E3%82%B2%E3%83%BC%E3%83%A0)#%E3%83%9F%E3%83%A5%E3%83%BC%E3%82%B8%E3%82%AB%E3%83%AB%E3%80%8C%E9%99%B0%E9%99%BD%E5%B8%AB%E3%80%8D%E3%80%9C%E5%B9%B3%E5%AE%89%E7%B5%B5%E5%B7%BB%E3%80%9C
<iframe title="Nintendo Switch 本体 (ニンテンドースイッチ) Joy-Con(L) ネオンブルー/(R) ネオンレッド" type="text/html" width="825" height="550" frameborder="0" allowfullscreen style="max-width:100%" src="https://read.amazon.com.au/kp/card?preview=inline&linkCode=kpd&ref_=k4w_oembed_RMHnlXyLRQgoac&asin=B07WXL5YPW&tag=kpembed-20"></iframe>
<iframe title="Nintendo Switch 本体 (ニンテンドースイッチ) Joy-Con(L) ネオンブルー/(R) ネオンレッド" type="text/html" width="825" height="550" frameborder="0" allowfullscreen style="max-width:100%" src="https://read.amazon.com.au/kp/card?preview=inline&linkCode=kpd&ref_=k4w_oembed_NAToYCXK5AdBM9&asin=B07WXL5YPW&tag=kpembed-20"></iframe>
https://www.amazon.co.jp/gp/video/detail/B07QBC423H/ref=atv_wl_hom_c_unkc_1_32</pre>
プロトコル必須
http(p)から始まることを条件にする場合、文章中なら5chのh抜き表記も考慮がいる
(?:h?ttps?:\/\/)(?:(?:[A-Za-z0-9\-.]+[.:])|(?:www\.|[-;:&=+$,\w]+@))(?:[A-Za-z0-9.-]+)(?:[/\-+=&;%@.\w_~()]*)(?:[.!/\\\w-?%#~&=+()]*)
相対指定URL
前述の正規表現は相対指定のURLに対応していない。
もし対応するなら専用の正規表現を用意する。
(\/{1}(?:[A-Za-z0-9.-]+)\/)([/\-+=&;%@.\w_~()]*)([.!/\\\w-?%#~&=+()]*)
これだけだと相対指定だけマッチする条件にはならない。
何らかの日本語的文字かスペースがURL前にあるかどうかを条件に含めれば、相対パスだけにマッチする。
([\u2000-\u2B90\u3000-\u30FF\u3220-\u33FE\u3400-\u9FFF\uF900-\uFAFF\uD840-\uD87F\uDC00-\uDFFF\uFF01-\uFFE6])
日本語ドメイン
ブラウザのアドレスバーからURLをコピーした場合、Punycode表記になるので、ここまでの正規表現で対応できる。
日本語.jp → xn--wgv71a119e.jp
ドメインを直接日本語で表記した場合、前述のUnicode正規表現で対応したいドメインの文字種別を判別すれば対応できる。Punycodeへの変換はJSDOMのライブラリを使えばよさそうだし、日本語.jpの日本語ドメインリストをスクレイピングして有効な日本語ドメインリストを作ることもできなくはない。
が、日本語ドメイン自体が下火なので、その労力を払ってまで対応したいとは思わなかった🙄