Laravel-Excel（Maatwebsite/Excel）CSVの解釈の検証

## Laravel-Excel のCSVの解釈の検証
Laravel-Excel（ｍaatwebsite/excel） のcsvインポートの際のcsvの記述の仕方による値の解釈がどうなるのか検証を行いました。検証は下記の`DummyImport`クラスインスタンスをExcelファサードの`toArray()`の引数として渡し、取得した行の配列の値の解釈を確認します。

```app/Import/DummyImport.php
<?php
namespace App\Import;
use Maatwebsite\Excel\Concerns\ToModel;
use Excel;
class DummyImport implements ToModel
{
    public function model(array $row)
    {
        return $row;
    }
}

//DummyImportインスタンスをExcelファサードの`toArray()`の第一引数として渡す。
//併せて、対象csvファイルへのパスを第二引数として渡す。
$data = Excel::toArray(new DummyImport(), $filepath);
```



## 検証1：文字リテラルの解釈
```case1.csv
"a","b","c"
a,b,c
```
クオーテーション`""`を付けない時、付ける時の違いがあるのか検証しました。


```tests/Unit/CSVExtractTest.php
<?php
namespace Tests\Unit;
use Excel;
use App\Import\DummyImport;
use Tests\TestCase;

class CSVExtractTest extends TestCase
{
    /** @test */
    public function CSV検証_文字列クオーテーションありなし()
    {
        $data = Excel::toArray(new DummyImport(), base_path().'/case1.csv');
        $this->assertEquals(2, \count($data[0]));

        //クオーテーションあり
        $this->assertEquals(3, \count($data[0][0]));
        $this->assertEquals('a', $data[0][0][0]);
        $this->assertEquals('b', $data[0][0][1]);
        $this->assertEquals('c', $data[0][0][2]);

        //クオーテーションなし
        $this->assertEquals(3, \count($data[0][1]));
        $this->assertEquals('a', $data[0][1][0]);
        $this->assertEquals('b', $data[0][1][1]);
        $this->assertEquals('c', $data[0][1][2]);
    }
}
```

```テスト結果.txt

Time: 5.22 seconds, Memory: 16.00 MB

OK (1 test, 9 assertions)
```

違いはないようでした。

## 検証2：カンマ入り文字列の解釈
文字列にカンマの入った `a,a` という文字列をインポートする場合はどうなるのか検証してみました

```case2.csv
"a,a","b","c"
a,a,b,c
"a,a",b,c
```
１列目はクオーテーション`""`をすべての値に付けました。２列目はクオーテーション`""`を付けません。（おそらくこれを３カラムと解釈されない。）3列目は`a,a`にだけクオーテーションを付けました。

```tests/Unit/CSVExtractTest.php
<?php
namespace Tests\Unit;
use Excel;
use App\Import\DummyImport;
use Tests\TestCase;

class CSVExtractTest extends TestCase
{
    protected $extractedData;
    public function setUp():void
    {
        parent::setUp();        
        $this->extractedData = Excel::toArray(new DummyImport(), base_path().'/case2.csv');
    }
    
    /** 中略 */

    /** @test */
    public function CSV検証_1列目_すべての値にクオーテーションを付ける()
    {
        $data = $this->extractedData;
        //１列目のカラム数は３であること
        $this->assertEquals(3, \count($data[0][0]));
        //値の検証
        $this->assertEquals('a,a', $data[0][0][0]);
        $this->assertEquals('b', $data[0][0][1]);
        $this->assertEquals('c', $data[0][0][2]);
    }

    /** @test */
    public function CSV検証_2列目_カンマの入った文字列にクオーテーションを付けない()
    {
        $data = $this->extractedData;
        //２列目のカラム数は３であること
        $this->assertEquals(3, \count($data[0][1]));
        //値の検証
        $this->assertEquals('a,a', $data[0][1][0]);
        $this->assertEquals('b', $data[0][1][1]);
        $this->assertEquals('c', $data[0][1][2]);
    }

    /** @test */
    public function CSV検証_3列目_カンマありのデータにだけクオーテーションを付ける
    {
        $data = $this->extractedData;
        //カラム数は３であること
        $this->assertEquals(3, \count($data[0][2]));
        //値の検証
        $this->assertEquals('a,a', $data[0][2][0]);
        $this->assertEquals('b', $data[0][2][1]);
        $this->assertEquals('c', $data[0][2][2]);
    }
}
```

```テスト結果.txt
FFF.                                                                4 / 4 (100%)

Time: 6.49 seconds, Memory: 16.00 MB

There were 3 failures:

1) Tests\Unit\CSVExtractTest::CSV検証_1列目_すべての値にクオーテーションを付ける
Failed asserting that 4 matches expected 3.

/home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:23

2) Tests\Unit\CSVExtractTest::CSV検証_2列目_カンマの入った文字列にクオーテーションを付けない
Failed asserting that 4 matches expected 3.

/home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:35

3) Tests\Unit\CSVExtractTest::CSV検証_3列目_カンマありのデータにだけクオーテーションを付ける
Failed asserting that 4 matches expected 3.

/home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:47

FAILURES!
Tests: 4, Assertions: 12, Failures: 3.
```
予想よりもエラーが多かったのですが、arrayのカラム数はファイル内最大のカラム数となるようでした。
カラム数のassertをコメントアウトして実行したところ、予想通り、取得される値は２列目が不正となり、１列目、３列目は有効でした。

```テスト結果.txt
PHPUnit 7.5.13 by Sebastian Bergmann and contributors.

.F..                                                                4 / 4 (100%)

Time: 6.23 seconds, Memory: 16.00 MB

There was 1 failure:

1) Tests\Unit\CSVExtractTest::CSV検証_2列目_カンマの入った文字列にクオーテーションを付けない
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'a,a'
+'a'

/home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:37
```


## 検証3：数値リテラル（整数、浮動小数点数）の検証
```case3.csv
1,-2147483648,2147483647
1.0,2.231224,00030141.213
```

```tests/Unit/CSVExtractTest.php
<?php
namespace Tests\Unit;
use Excel;
use App\Import\DummyImport;
use Tests\TestCase;

class CSVExtractTest extends TestCase
{
    /** 中略 */

    public function CSV検証_整数、浮動小数点数()
    {
        $data = Excel::toArray(new DummyImport(), base_path().'/case3.csv');
        $this->assertEquals(2, \count($data[0]));

        //整数
        $this->assertEquals(3, \count($data[0][0]));
        $this->assertEquals(1, $data[0][0][0]);
        $this->assertEquals(-2147483648, $data[0][0][1]);
        $this->assertEquals(2147483647, $data[0][0][2]);
        //浮動小数点数
        $this->assertEquals(3, \count($data[0][1]));
        $this->assertSame(1.0, $data[0][1][0]);
        $this->assertSame(2.231224, $data[0][1][1]);
        $this->assertSame(30141.213, $data[0][1][2]);
    }
}

```

```テスト結果.txt
PHPUnit 7.5.13 by Sebastian Bergmann and contributors.

...F                                                                4 / 4 (100%)

Time: 5.61 seconds, Memory: 16.00 MB

There was 1 failure:

1) Tests\Unit\CSVExtractTest::CSV検証_整数、浮動小数点数
Failed asserting that '00030141.213' is identical to 30141.213.

/home/vagrant/code/ttn-1129-laravel/tests/Unit/CSVExtractTest.php:88

FAILURES!
Tests: 4, Assertions: 24, Failures: 1.

```
00030141.213は文字列として扱うようでした。

## 検証4：特殊文字を含む場合
エスケープで使うバックスラッシュ`\`などを含んだ文字列でcsvファイルから値を取得します。

```case4.csv
@#@!@$!#$,^^^^^32143()_----,\\++====51`5
```


```tests/Unit/CSVExtractTest.php
<?php
namespace Tests\Unit;
use Excel;
use App\Import\DummyImport;
use Tests\TestCase;

class CSVExtractTest extends TestCase
{
    /** 中略 */

    /** @test */
    public function CSV検証_特殊文字を含む場合()
    {
        $data = Excel::toArray(new DummyImport(), base_path().'/case4.csv');
        $this->assertEquals(1, \count($data[0]));

        //整数
        $this->assertEquals(3, \count($data[0][0]));
        $this->assertEquals('@#@!@$!#$', $data[0][0][0]);
        $this->assertEquals('^^^^^32143()_----', $data[0][0][1]);
        $this->assertEquals('\\\\++====51`5', $data[0][0][2]);
    }
}
```

```テスト結果.txt
PHPUnit 7.5.13 by Sebastian Bergmann and contributors.

.....                                                               5 / 5 (100%)

Time: 5.96 seconds, Memory: 16.00 MB

OK (5 tests, 29 assertions)
```
バックスラッシュ`\`だけ、php側で、エスケープをちゃんとすることで検証できるようでした。

## 参照
Laravel/Excelのインストール等に関しましては @rito328 さんのこちらのサイトに詳しく書いて頂いておりましたので参考にさせて頂きました。
https://www.ritolab.com/entry/160


以上です。