前回の「空白文字の入力をトリムする」の続きです。

まず、動作確認を簡単にするために、ユニットテストを作成しましょう。

入力画面のユニットテストをもとに、いろいろなデータをテストできるように、データプロバイダーを使用します。


use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;

class SignupTest extends TestCase
{
    use DatabaseTransactions;

    /**
     * @dataProvider providerTrimpInput
     */
    public function testTrimpInput($last_name, $expected)
    {
        $this->visit('/signup')
            ->type('success@gmail.com', 'email')
            ->type('testtest', 'password')
            ->type('testtest', 'password_confirmation')
            ->type($last_name, 'last_name')
            ->type('太郎', 'first_name')
            ->press('保存')
            ->see('会員登録完了');

        $member = \App\Member::where('email', 'success@gmail.com')->first();

        $this->assertEquals($expected, $member->last_name);
    }

    public function providerTrimpInput()
    {
        return [
            [ '山田', '山田'],
            [ ' 山田 ', '山田'],   //半角スペース
            [ ' 山田 ', '山田'], //全角スペース
        ];
    }
}

ユニットテストのデータプロバイダーは、テストとデータを分けることにより、1つのテストでいろいろなデータのテストが可能となります。必要なのは、コメントのphpDocの@dataProviderでデータを供給する関数名を指定することと、そのデータ供給の関数を作成することです。この例では3つのデータを用意することにより、3回テストが実行されます。

テスト実行結果は、以下です。

PHPUnit 4.8.9 by Sebastian Bergmann and contributors.

..F

Time: 360 ms, Memory: 26.50Mb

There was 1 failure:

1) SignupTest::testTrimpInput with data set #2 (' 山田 ', '山田')
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'山田'
+' 山田 '

/vol1/usr/www/shop/webdocs/demo/tests/SignupTest.php:27

FAILURES!
Tests: 3, Assertions: 12, Failures: 1.

2番目の半角のスペースのデータはトリムされ成功となり、3番目の全角スペースが前後にあるデータでは失敗となります。

さて、全角スペースはどう対応しましょうか?

再度、trim関数の仕様を見てみましょう。

 string trim ( string $str [, string $character_mask = " \t\n\r\0\x0B" ] )

この関数は str の最初および最後から空白文字を取り除き、 取り除かれた文字列を返します。
2番目のパラメータを指定しない場合、 trim()は以下の文字を削除します。

    " " (ASCII 32 (0x20)), 通常の空白。
    "\t" (ASCII 9 (0x09)), タブ。
    "\n" (ASCII 10 (0x0A)), リターン。
    "\r" (ASCII 13 (0x0D)), 改行。
    "\0" (ASCII 0 (0x00)), NULバイト
    "\x0B" (ASCII 11 (0x0B)), 垂直タブ

そう、2番目のパラメータに全角スペースを入れてあげればよいですね。

trim($val, ' \t\n\r\0\x0B ');//全角スペースは最後の空白文字

しかし、これはテストしたところうまくいきませんでした。全角のスペースが入る値には対応するようですが、半角の文字列では文字列によっては空白文字でないものもトリムしてしまいます。trimの関数はユニコード対応でないようですね。それならば、mb_trimと思いますが、残念ながらこれが存在しません。

いろいろ調べたところ、preg_replaceが使えそうです。

パターンは、

'/(^\s+)|(\s+$)/u'

\sは空白文字のエスケープシーケンスであり、ドキュメントでは以下の記述があります。

エスケープシーケンス

空白文字とは HT (9)、LF (10)、FF (12)、CR (13)、スペース (32) のことです。 しかし、ロケールを指定したマッチングを行った場合には、128から255までのコードポイントの文字 (たとえば NBSP (A0)) も空白文字とみなされる可能性があります。

ということで、trimで削除する空白文字とともにユニコードの全角スペースも削除してくれます。

ミドルウェアを書き直すと、

namespace App\Http\Middleware; 

use Closure; class TrimInput {

    /** 
     * Handle an incoming request. 
     * 
     * @param \Illuminate\Http\Request $request 
     * @param \Closure $next 
     * @return mixed 
     */ 
    public function handle($request, Closure $next) { 

        $input = $request->all();

        $trimmed = [];

        foreach($input as $key => $val)
        {
            $trimmed[$key] = preg_replace('/(^\s+)|(\s+$)/u', '', $value);
        }

        $request->merge($trimmed);

        return $next($request);
    }
}

先のユニットテストの結果は?

PHPUnit 4.8.9 by Sebastian Bergmann and contributors.

...

Time: 359 ms, Memory: 26.50Mb

OK (3 tests, 12 assertions)

成功です!

次回は、配列の入力値の個々の値の空白文字のトリムの対応です。

By khino