CODE Polyglot / 入門 / 第17回

問い合わせフォーム — 5つの項目をそろえて確かめる

名前・メールアドレス・郵便番号・電話番号・本文の5つを受け取り、全角を半角にそろえてから、正しい形かを確かめます。これまでの回の部品を組み合わせた、最初の「動くフォーム」です。このページから実際に送って、10言語の答えを見比べられます。

動かしてみる

入力して送ると、このページの下に載せたプログラムがサーバーの上で実際に動いて、答えを返します。 ブラウザの側では何も確かめません。送った内容は、どこにも届けず、保存もしません。

入力の例

しばらく使われていないと、最初の1回は答えまで数秒から20秒ほどかかります。

ここに答えが出ます。まずは「入力の例」を押して、送ってみてください。

画面にこう出れば正解

どの言語で書いても、同じ入力なら画面に出る文字は1文字も違わない、というのが正解の決め方です(例は Python で動かしたときのコマンドです)。正解表の36件のうち4件を載せています。すべての件を、毎朝10言語で動かして確かめています。

すべて正しい

$ python3 form.py "山田 太郎" taro@example.com 123-4567 03-1234-5678 資料をお送りください。
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。

全角で入力(そろえてから確かめる)

$ python3 form.py  山田 太郎  taro@example.com 1234567 03-1234-5678 資料をお送りください。
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。

郵便番号と電話番号は空でよい

$ python3 form.py "山田 太郎" taro@example.com "" "" 資料をお送りください。
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK (なし)
電話番号 OK (なし)
本文 OK 11文字 資料をお送りください。

全部まちがい

$ python3 form.py "" taro@ 123 123 ""
NG
名前 NG 入力してください
メール NG メールアドレスの形ではありません
郵便番号 NG 半角の数字7桁で入力してください(例 123-4567)
電話番号 NG 0から始まる数字10桁か11桁で入力してください(例 03-1234-5678)
本文 NG 入力してください
正解表の36件をすべて見る
入力画面に出る答え
c001 すべて正しい山田 太郎taro@example.com123-456703-1234-5678資料をお送りください。
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c002 全角で入力(そろえてから確かめる) 山田 太郎 taro@example.com123456703-1234-5678資料をお送りください。
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c003 郵便番号と電話番号は空でよい山田 太郎taro@example.com(空)(空)資料をお送りください。
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK (なし)
電話番号 OK (なし)
本文 OK 11文字 資料をお送りください。
c004 名前が空(空)taro@example.com123-456703-1234-5678資料をお送りください。
NG
名前 NG 入力してください
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c005 名前が空白だけ  \ttaro@example.com123-456703-1234-5678資料をお送りください。
NG
名前 NG 入力してください
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c006 名前の途中に改行山田\n太郎taro@example.com123-456703-1234-5678資料をお送りください。
NG
名前 NG 改行やタブは使えません
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c007 名前がちょうど50文字(絵文字も1文字)🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣…(50文字)taro@example.com123-456703-1234-5678資料をお送りください。
OK
名前 OK 🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c008 名前が51文字🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣…(51文字)taro@example.com123-456703-1234-5678資料をお送りください。
NG
名前 NG 50文字以内で入力してください
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c009 名前に半角カナ(そのまま)ヤマダ タロウtaro@example.com123-456703-1234-5678資料をお送りください。
OK
名前 OK ヤマダ タロウ
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c010 メールが空山田 太郎(空)123-456703-1234-5678資料をお送りください。
NG
名前 OK 山田 太郎
メール NG 入力してください
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c011 メールにドメインの点がない山田 太郎taro@example123-456703-1234-5678資料をお送りください。
NG
名前 OK 山田 太郎
メール NG メールアドレスの形ではありません
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c012 メールの点が続く山田 太郎taro..yamada@example.com123-456703-1234-5678資料をお送りください。
NG
名前 OK 山田 太郎
メール NG メールアドレスの形ではありません
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c013 メールの最後に改行(前後の空白として取る)山田 太郎taro@example.com\n123-456703-1234-5678資料をお送りください。
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c014 メールの途中に改行山田 太郎hello\ntaro@example.com123-456703-1234-5678資料をお送りください。
NG
名前 OK 山田 太郎
メール NG メールアドレスの形ではありません
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c015 メールにひらがな山田 太郎たろう@example.com123-456703-1234-5678資料をお送りください。
NG
名前 OK 山田 太郎
メール NG メールアドレスの形ではありません
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c016 郵便番号がハイフンなし山田 太郎taro@example.com123456703-1234-5678資料をお送りください。
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c017 郵便番号のハイフンが長音「ー」山田 太郎taro@example.com123ー456703-1234-5678資料をお送りください。
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c018 郵便番号のハイフンがマイナス記号「−」山田 太郎taro@example.com123−456703-1234-5678資料をお送りください。
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c019 郵便番号が6桁山田 太郎taro@example.com123-45603-1234-5678資料をお送りください。
NG
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 NG 半角の数字7桁で入力してください(例 123-4567)
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c020 郵便番号に全角の数字以外(①)山田 太郎taro@example.com①23-456703-1234-5678資料をお送りください。
NG
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 NG 半角の数字7桁で入力してください(例 123-4567)
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c021 電話番号がハイフンなし11桁山田 太郎taro@example.com123-456709012345678資料をお送りください。
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 09012345678
本文 OK 11文字 資料をお送りください。
c022 電話番号が9桁山田 太郎taro@example.com123-456703-1234-567資料をお送りください。
NG
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 NG 0から始まる数字10桁か11桁で入力してください(例 03-1234-5678)
本文 OK 11文字 資料をお送りください。
c023 電話番号が0から始まらない山田 太郎taro@example.com123-45671234567890資料をお送りください。
NG
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 NG 0から始まる数字10桁か11桁で入力してください(例 03-1234-5678)
本文 OK 11文字 資料をお送りください。
c024 電話番号のハイフンが続く山田 太郎taro@example.com123-456703--1234-5678資料をお送りください。
NG
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 NG 0から始まる数字10桁か11桁で入力してください(例 03-1234-5678)
本文 OK 11文字 資料をお送りください。
c025 電話番号に +81山田 太郎taro@example.com123-4567+81-3-1234-5678資料をお送りください。
NG
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 NG 0から始まる数字10桁か11桁で入力してください(例 03-1234-5678)
本文 OK 11文字 資料をお送りください。
c026 本文が空山田 太郎taro@example.com123-456703-1234-5678(空)
NG
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 NG 入力してください
c027 本文が改行だけ山田 太郎taro@example.com123-456703-1234-5678\r\n\r\n
NG
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 NG 入力してください
c028 本文の改行は \r\n でも1文字(ブラウザは \r\n で送る)山田 太郎taro@example.com123-456703-1234-56781行目\r\n2行目
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 7文字 1行目 2行目
c029 本文がちょうど1000文字(\r\n を含む)山田 太郎taro@example.com123-456703-1234-5678あい\r\nあい\r\nあい\r\nあい\r\nあい\r\nあい\r\nあい\r…(1333文字)
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 1000文字 あい あい あい あい あい あい あい あい あい あい …
c030 本文が1001文字山田 太郎taro@example.com123-456703-1234-5678あい\r\nあい\r\nあい\r\nあい\r\nあい\r\nあい\r\nあい\r…(1334文字)
NG
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 NG 1000文字以内で入力してください
c031 本文の先頭30文字(絵文字)山田 太郎taro@example.com123-456703-1234-5678🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 31文字 🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣🍣…
c032 本文がちょうど30文字山田 太郎taro@example.com123-456703-1234-5678ああああああああああああああああああああああああああああああ
OK
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 30文字 ああああああああああああああああああああああああああああああ
c033 全部まちがい(空)taro@123123(空)
NG
名前 NG 入力してください
メール NG メールアドレスの形ではありません
郵便番号 NG 半角の数字7桁で入力してください(例 123-4567)
電話番号 NG 0から始まる数字10桁か11桁で入力してください(例 03-1234-5678)
本文 NG 入力してください
c034 メールのローカル部が長い(点で区切った部分が4500個)山田 太郎a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.…(9011文字)123-456703-1234-5678資料をお送りください。
OK
名前 OK 山田 太郎
メール OK a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a@example.com
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c035 メールのドメインが長い(点で区切った部分が4500個・最後が数字)山田 太郎taro@a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a…(9006文字)123-456703-1234-5678資料をお送りください。
NG
名前 OK 山田 太郎
メール NG メールアドレスの形ではありません
郵便番号 OK 123-4567
電話番号 OK 03-1234-5678
本文 OK 11文字 資料をお送りください。
c036 電話番号のハイフンが4500個山田 太郎taro@example.com123-45670-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-0-…(9001文字)資料をお送りください。
NG
名前 OK 山田 太郎
メール OK taro@example.com
郵便番号 OK 123-4567
電話番号 NG 0から始まる数字10桁か11桁で入力してください(例 03-1234-5678)
本文 OK 11文字 資料をお送りください。

10言語のプログラム

どれもそのまま保存して動かせます。毎朝、上の正解の例をすべて実際に動かして確かめています。

form.php8.4.26 で 36 / 36 件の出力が正解と一致

<?php
// 問い合わせフォームの5つの項目をそろえて、正しいかを確かめる
const TRIM = " \t\n\r"; // 全角スペースは、先に半角にしてから取る
const HYPHENS = ['‐', '−', 'ー', 'ー']; // ハイフンに似た文字(全角の「-」は半角にする処理で「-」になる)
const LOCAL = '[A-Za-z0-9_+-]+(\.[A-Za-z0-9_+-]+)*';
const LABEL = '[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?';

// 全角の英数字・記号(U+FF01〜FF5E)と全角スペースを半角にする(第9回)。
// mbstring 拡張が無い環境でも動くように、文字の番号から文字を作るのに html_entity_decode(&#番号; の形)を使い、対応表で置き換える
function to_half(string $s): string
{
    static $table = null;
    if ($table === null) {
        $table = [" " => " "];
        for ($code = 0x21; $code <= 0x7E; $code++) {
            $table[html_entity_decode("&#" . ($code + 0xFEE0) . ";", ENT_QUOTES, "UTF-8")] = chr($code);
        }
    }
    return strtr($s, $table);
}

// strlen はバイトで数えるので、/u を付けた preg_split で1文字ずつの配列にする(mb_strlen は mbstring が無いと使えない)
function chars(string $s): array
{
    return preg_split('//u', $s, -1, PREG_SPLIT_NO_EMPTY);
}

// trim はバイトで取るので、全角スペース(3バイト)は取れない。先に半角にしてから取る
function tidy(string $s): string
{
    return trim(to_half($s), TRIM);
}

// 項目ごとに [正しいか, そろえた値か理由] を返す
function check_name(string $v): array
{
    $v = tidy($v);
    if ($v === '') return [false, '入力してください'];
    if (preg_match('/[\t\n\r]/', $v)) return [false, '改行やタブは使えません'];
    if (count(chars($v)) > 50) return [false, '50文字以内で入力してください'];
    return [true, $v];
}

function check_email(string $v): array
{
    $v = tidy($v);
    if ($v === '') return [false, '入力してください'];
    // 「$」は最後の改行の前にも合うので、文字列の本当の最後を表す「\z」を使う
    if (!preg_match('/\A' . LOCAL . '@(' . LABEL . '\.)+[A-Za-z]{2,}\z/', $v)) {
        return [false, 'メールアドレスの形ではありません'];
    }
    return [true, $v];
}

function check_zip(string $v): array
{
    $v = str_replace(HYPHENS, '-', tidy($v));
    if ($v === '') return [true, '(なし)'];
    if (!preg_match('/\A[0-9]{3}-?[0-9]{4}\z/', $v)) return [false, '半角の数字7桁で入力してください(例 123-4567)'];
    return [true, substr($v, 0, 3) . '-' . substr($v, -4)];
}

function check_tel(string $v): array
{
    $v = str_replace(HYPHENS, '-', tidy($v));
    if ($v === '') return [true, '(なし)'];
    $digits = str_replace('-', '', $v);
    // ハイフンは数字の間に1つずつ。0から始まり、数字は10桁か11桁
    if (!preg_match('/\A[0-9]+(-[0-9]+)*\z/', $v) || $digits[0] !== '0' || !in_array(strlen($digits), [10, 11], true)) {
        return [false, '0から始まる数字10桁か11桁で入力してください(例 03-1234-5678)'];
    }
    return [true, $v];
}

function check_body(string $v): array
{
    // ブラウザは改行を \r\n で送るので、\n にそろえてから数える
    $v = str_replace(["\r\n", "\r"], "\n", $v);
    $v = preg_replace('/\A[ \t\n\r\x{3000}]+|[ \t\n\r\x{3000}]+\z/u', '', $v);
    if ($v === '') return [false, '入力してください'];
    $c = chars(str_replace("\n", ' ', $v));
    $n = count($c);
    if ($n > 1000) return [false, '1000文字以内で入力してください'];
    $preview = $n > 30 ? implode('', array_slice($c, 0, 30)) . '…' : implode('', $c);
    return [true, "{$n}文字 {$preview}"];
}

$fields = [['名前', 'check_name'], ['メール', 'check_email'], ['郵便番号', 'check_zip'], ['電話番号', 'check_tel'], ['本文', 'check_body']];
$rows = [];
foreach ($fields as $i => [$label, $check]) {
    $rows[] = [$label, ...$check($argv[$i + 1])];
}
echo (array_product(array_column($rows, 1)) ? 'OK' : 'NG') . "\n";
foreach ($rows as [$label, $ok, $text]) {
    echo $label . ' ' . ($ok ? 'OK' : 'NG') . ' ' . $text . "\n";
}

動かし方(ファイルを保存したフォルダで) ・ PHP を入れる

$ php form.php "山田 太郎" taro@example.com 123-4567 03-1234-5678 資料をお送りください。

この回でやること

  • フォームで受け取った5つの項目を、そろえてから確かめる(全角を半角に・前後の空白を取る・改行をそろえる)
  • 正しくない項目には、直し方の分かる理由を返す
  • 同じ入力を10言語に送り、10言語の答えが1文字も違わないことを確かめる

これまでの回が、そのまま部品になります。

部品使うところ
第9回 全角を半角に名前・メール・郵便番号・電話番号
第7回 郵便番号の形郵便番号
第16回 メールアドレスの形メール
第4回・第15回 文字数・先頭だけ出す名前の文字数・本文の文字数とプレビュー

この回の決まり

プログラムは、5つの項目を引数で受け取り(名前・メール・郵便番号・電話番号・本文の順。空の項目は空の文字列)、1行目に OK(全部正しい)か NG を、続けて項目ごとに <項目> OK <そろえた値> か <項目> NG <理由> を出します。

項目必須決まり
名前○半角にして前後の空白を取る。途中に改行・タブがあれば NG。50文字まで
メール○半角にして前後の空白を取ってから、第16回の形を確かめる(全角の @ も通る)
郵便番号半角にして、ハイフンに似た文字(‐ − ー ー)を - に。123-4567 か 1234567。出すときは 123-4567 の形
電話番号郵便番号と同じくそろえる。数字とハイフンだけで、0から始まり、数字が10桁か11桁
本文○改行を \n にそろえてから前後の空白を取る。1000文字まで。先頭30文字のプレビューを付ける
  • 前後の空白として取るのは、半角スペース・タブ・改行・全角スペースだけです
  • 文字数は Unicode の文字(コードポイント)で数えます。絵文字も1文字です
  • 郵便番号・電話番号は空でもかまいません((なし) と出します)

解説

確かめる前に、そろえる

人が入力する値には、全角の数字(1234567)、全角の @、うっかり入った前後の空白、長音「ー」のハイフンなどが混ざります。そのまま正規表現で確かめると、正しい内容なのに NG になります。この回では、先にそろえてから、形を確かめる順番にしています。そろえた値を返すので、保存するときもそろった形で残せます。

「前後の空白を取る」関数は、言語ごとに取る文字が違う

どの言語にも前後の空白を取る関数がありますが、何を空白とみなすかが違います。PHP の trim は全角スペースを取りません。一方、JavaScript の trim()・Java の strip()・C# の Trim()・Go の strings.TrimSpace・Rust の trim()・Kotlin の trim() は、全角スペースのほかにも、いくつかの空白の文字を取ります。

10言語で答えをそろえるため、この回では取る文字(半角スペース・タブ・\n・\r)を決めて、それだけを取る書き方にしました。全角スペースは、先に半角にしてから取ります。

文字数は「Unicode の文字」で数える

length が何を数えるかも、言語ごとに違います(第4回)。

数え方言語この回での書き方
Unicode の文字Python・Rubylen・length そのまま
UTF-16 の単位(絵文字1つが 2)JavaScript・Java・C#・Kotlin[...s]・codePointCount・EnumerateRunes
バイト(絵文字1つが 4)PHP・Go・Rustpreg_split('//u', …)・utf8.RuneCountInString・chars().count()
見た目の1文字(書記素)SwiftunicodeScalars.count

ブラウザは、改行を \r\n で送る

フォームの複数行の欄(textarea)の改行は、送るときに \r\n(2文字)になります。そのまま数えると、改行1つが2文字になり、ちょうど1000文字の本文が NG になります(正解表の c029)。本文は、\r\n と \r を \n にそろえてから数えています。下の「動かしてみる」も、ふつうのフォームと同じく改行を \r\n にして送っています。

Swift の String は \r\n を1つの文字として扱うので、前後を取るときも Unicode の文字(unicodeScalars)で見ています。

引数で受け取る理由

ブラウザとサーバーのやりとりは JSON ですが、各言語のプログラムは引数で受け取り、決まった形の行を出すだけにしました。Java・Kotlin・Rust は、標準の機能だけでは JSON を読めない(ライブラリが要る)ためです。JSON を読んで各言語のプログラムに引数で渡し、出した行を JSON に直してブラウザに返すところは、サーバーの入口(Python)が受け持っています。

作ってから分かったこと:PHP の mbstring

最初に PHP を mb_strlen・mb_str_split で書いて、毎朝の検証に使う Linux のコンテナで動かすと、当時の正解表33件中0件でした。コンテナの PHP には mbstring 拡張が入っておらず、mb_strlen が無いので止まっていました。mb_ で始まる関数は、PHP に必ず入っているとは限りません。この回の PHP は、preg_split('//u', …) で1文字ずつに分けて数える書き方にしています。

作ってから分かったこと:Java の正規表現は、長い繰り返しで止まる

公開したあと、メールアドレスに a.a.a.… と「.」で区切った部分を4500個並べて送ると、Java と Kotlin のプログラムだけが止まり、10言語の答えが割れました(正解表の c034〜c036)。

Java の正規表現は、(\.[A-Za-z0-9_+-]+)* のように ( ) を繰り返す部分を、繰り返し1回ごとに再帰で調べます。繰り返しが数千回になると、再帰の深さの上限を超えて StackOverflowError で止まります。この Mac の Java 21 では、2000個では動き、4500個で止まりました。Kotlin の Regex は Java の正規表現を使うので、同じように止まります。ほかの8言語は、同じ正規表現でも止まりませんでした。

Java と Kotlin は、「@」と「.」(電話番号は「-」)で先に分けてから、部分ごとに繰り返しのない正規表現で確かめる書き方に直しました。決まりの意味は変わっていません。第16回 の Java・Kotlin も同じ書き方だったので、あわせて直しています。

動かしているところ

「動かしてみる」で送った内容は、AWS の上の1つのプログラム(AWS Lambda)が受け取り、このページに載せている10言語のプログラムをそのまま動かして答えを返します。毎朝の検証と同じ環境(10言語が入ったコンテナ)です。

  • 送った内容は、どこにも届けず、保存もしません(記録にも入力の中身は書きません)
  • しばらく使われていないと、最初の1回は答えまで数秒から20秒ほどかかります
  • 1秒に2回まで、入力は全体で10,000バイトまでです。短い時間にたくさん呼ばれると、いたずらとみなして自動で止まります

練習

  1. 「会社名」の項目を足してみましょう(任意。100文字まで)
  2. 電話番号を、ハイフンなしでも 03-1234-5678 の形にそろえて返すには、どんな決まりが要るか考えてみましょう(市外局番の長さは地域で違います)