mirror of
https://github.com/PHPOffice/PhpSpreadsheet.git
synced 2026-08-24 12:28:36 +00:00
ae80c12ef0
This PR came about as I pondered how feasible it was to change the default escape character from backslash to null string, since the latter emulates Excel's own actions. Also, surveying issues relating to CSV, it seems that people are often in a situation where the current defaults aren't optimal for them (e.g. they are in a region where semicolon rather than comma is a better default delimiter). My case and that case can both be handled by methods after a reader is constructed. However, the issues also show that many use `IOFactory::load` rather than `new Csv()`, and the methods to affect the defaults are not available in that case. Adding a static callback that can be invoked by the constructor addresses all these problems. This can be set as part of the user application's normal initialization, and no special attention needs to be paid to CSV loads thereafter, no matter how they are invoked. This also makes it feasible to use 'guess' as inputEncoding, by providing a new setFallbackEncoding (default CP1252) method to use if none of the heuristic tests pass. There was already the ability to guess the encoding before `$reader->load()`, but not before `IOFactory::load`. Almost all typehints in Reader/Csv and Reader/Csv/Delimiter are now part of the function signature rather than in the DocBlock. The exceptions are one method in Delimiter which uses a `resource` parameter, and the `canRead` and `load` methods, which must match the signature in IOFactory. I will look into changing those later. The Csv Reader tests are moved into their own directory. All Phpstan baseline entries involving Csv Reader are eliminated.
123 lines
4.5 KiB
PHP
123 lines
4.5 KiB
PHP
<?php
|
|
|
|
namespace PhpOffice\PhpSpreadsheetTests\Reader\Csv;
|
|
|
|
use PhpOffice\PhpSpreadsheet\Reader\Csv;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
class CsvEncodingTest extends TestCase
|
|
{
|
|
/**
|
|
* @dataProvider providerEncodings
|
|
*
|
|
* @param string $filename
|
|
* @param string $encoding
|
|
*/
|
|
public function testEncodings($filename, $encoding): void
|
|
{
|
|
$reader = new Csv();
|
|
$reader->setInputEncoding($encoding);
|
|
$spreadsheet = $reader->load($filename);
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
self::assertEquals('Å', $sheet->getCell('A1')->getValue());
|
|
}
|
|
|
|
/**
|
|
* @dataProvider providerEncodings
|
|
*
|
|
* @param string $filename
|
|
* @param string $encoding
|
|
*/
|
|
public function testWorkSheetInfo($filename, $encoding): void
|
|
{
|
|
$reader = new Csv();
|
|
$reader->setInputEncoding($encoding);
|
|
$info = $reader->listWorksheetInfo($filename);
|
|
self::assertEquals('Worksheet', $info[0]['worksheetName']);
|
|
self::assertEquals('B', $info[0]['lastColumnLetter']);
|
|
self::assertEquals(1, $info[0]['lastColumnIndex']);
|
|
self::assertEquals(2, $info[0]['totalRows']);
|
|
self::assertEquals(2, $info[0]['totalColumns']);
|
|
}
|
|
|
|
public function providerEncodings(): array
|
|
{
|
|
return [
|
|
['tests/data/Reader/CSV/encoding.iso88591.csv', 'ISO-8859-1'],
|
|
['tests/data/Reader/CSV/encoding.utf8.csv', 'UTF-8'],
|
|
['tests/data/Reader/CSV/encoding.utf8bom.csv', 'UTF-8'],
|
|
['tests/data/Reader/CSV/encoding.utf16be.csv', 'UTF-16BE'],
|
|
['tests/data/Reader/CSV/encoding.utf16le.csv', 'UTF-16LE'],
|
|
['tests/data/Reader/CSV/encoding.utf32be.csv', 'UTF-32BE'],
|
|
['tests/data/Reader/CSV/encoding.utf32le.csv', 'UTF-32LE'],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @dataProvider providerGuessEncoding
|
|
*/
|
|
public function testGuessEncoding(string $filename): void
|
|
{
|
|
$reader = new Csv();
|
|
$reader->setInputEncoding(Csv::guessEncoding($filename));
|
|
$spreadsheet = $reader->load($filename);
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
self::assertEquals('première', $sheet->getCell('A1')->getValue());
|
|
self::assertEquals('sixième', $sheet->getCell('C2')->getValue());
|
|
}
|
|
|
|
/**
|
|
* @dataProvider providerGuessEncoding
|
|
*/
|
|
public function testFallbackEncoding(string $filename): void
|
|
{
|
|
$reader = new Csv();
|
|
$reader->setInputEncoding(Csv::GUESS_ENCODING);
|
|
$spreadsheet = $reader->load($filename);
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
self::assertEquals('première', $sheet->getCell('A1')->getValue());
|
|
self::assertEquals('sixième', $sheet->getCell('C2')->getValue());
|
|
}
|
|
|
|
public function providerGuessEncoding(): array
|
|
{
|
|
return [
|
|
['tests/data/Reader/CSV/premiere.utf8.csv'],
|
|
['tests/data/Reader/CSV/premiere.utf8bom.csv'],
|
|
['tests/data/Reader/CSV/premiere.utf16be.csv'],
|
|
['tests/data/Reader/CSV/premiere.utf16bebom.csv'],
|
|
['tests/data/Reader/CSV/premiere.utf16le.csv'],
|
|
['tests/data/Reader/CSV/premiere.utf16lebom.csv'],
|
|
['tests/data/Reader/CSV/premiere.utf32be.csv'],
|
|
['tests/data/Reader/CSV/premiere.utf32bebom.csv'],
|
|
['tests/data/Reader/CSV/premiere.utf32le.csv'],
|
|
['tests/data/Reader/CSV/premiere.utf32lebom.csv'],
|
|
['tests/data/Reader/CSV/premiere.win1252.csv'],
|
|
];
|
|
}
|
|
|
|
public function testGuessEncodingDefltIso2(): void
|
|
{
|
|
$filename = 'tests/data/Reader/CSV/premiere.win1252.csv';
|
|
$reader = new Csv();
|
|
$reader->setInputEncoding(Csv::guessEncoding($filename, 'ISO-8859-2'));
|
|
$spreadsheet = $reader->load($filename);
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
self::assertEquals('premičre', $sheet->getCell('A1')->getValue());
|
|
self::assertEquals('sixičme', $sheet->getCell('C2')->getValue());
|
|
}
|
|
|
|
public function testFallbackEncodingDefltIso2(): void
|
|
{
|
|
$filename = 'tests/data/Reader/CSV/premiere.win1252.csv';
|
|
$reader = new Csv();
|
|
self::assertSame('CP1252', $reader->getFallbackEncoding());
|
|
$reader->setInputEncoding(Csv::GUESS_ENCODING);
|
|
$reader->setFallbackEncoding('ISO-8859-2');
|
|
$spreadsheet = $reader->load($filename);
|
|
$sheet = $spreadsheet->getActiveSheet();
|
|
self::assertEquals('premičre', $sheet->getCell('A1')->getValue());
|
|
self::assertEquals('sixičme', $sheet->getCell('C2')->getValue());
|
|
}
|
|
}
|