Implement missing BAHTTEXT function

This commit is contained in:
Robin van der Vliet
2025-11-16 18:02:10 +01:00
parent ee2d4e8e39
commit 122b36b09f
7 changed files with 276 additions and 4 deletions
+1 -1
View File
@@ -525,7 +525,7 @@ Excel Function | PhpSpreadsheet Function
-------------------------|--------------------------------------
ARRAYTOTEXT | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Text::fromArray
ASC | **Not yet Implemented**
BAHTTEXT | **Not yet Implemented**
BAHTTEXT | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Thai::getBahtText
CHAR | \PhpOffice\PhpSpreadsheet\Calculation\TextData\CharacterConvert::character
CLEAN | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Trim::nonPrintable
CODE | \PhpOffice\PhpSpreadsheet\Calculation\TextData\CharacterConvert::code
@@ -43,7 +43,7 @@ AVERAGEIFS | STATISTICAL | Statistical\Conditional::AVER
Excel Function | Category | PhpSpreadsheet Function
-------------------------|-----------------------|--------------------------------------
BAHTTEXT | TEXT_AND_DATA | **Not yet Implemented**
BAHTTEXT | TEXT_AND_DATA | TextData\Thai::getBahtText
BASE | MATH_AND_TRIG | MathTrig\Base::evaluate
BESSELI | ENGINEERING | Engineering\BesselI::BESSELI
BESSELJ | ENGINEERING | Engineering\BesselJ::BESSELJ
+1 -1
View File
@@ -39,7 +39,7 @@ AVERAGEIFS | CATEGORY_STATISTICAL | \PhpOffice\PhpSpread
Excel Function | Category | PhpSpreadsheet Function
-------------------------|--------------------------------|--------------------------------------
BAHTTEXT | CATEGORY_TEXT_AND_DATA | **Not yet Implemented**
BAHTTEXT | CATEGORY_TEXT_AND_DATA | \PhpOffice\PhpSpreadsheet\Calculation\TextData\Thai::getBahtText
BASE | CATEGORY_MATH_AND_TRIG | \PhpOffice\PhpSpreadsheet\Calculation\MathTrig\Base::evaluate
BESSELI | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering\BesselI::BESSELI
BESSELJ | CATEGORY_ENGINEERING | \PhpOffice\PhpSpreadsheet\Calculation\Engineering\BesselJ::BESSELJ
@@ -149,7 +149,7 @@ class FunctionArray extends CalculationBase
],
'BAHTTEXT' => [
'category' => Category::CATEGORY_TEXT_AND_DATA,
'functionCall' => [Functions::class, 'DUMMY'],
'functionCall' => [TextData\Thai::class, 'getBahtText'],
'argumentCount' => '1',
],
'BASE' => [
@@ -0,0 +1,137 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Calculation\TextData;
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
class Thai
{
use ArrayEnabled;
private const THAI_DIGITS = [
0 => 'ศูนย์',
1 => 'หนึ่ง',
2 => 'สอง',
3 => 'สาม',
4 => 'สี่',
5 => 'ห้า',
6 => 'หก',
7 => 'เจ็ด',
8 => 'แปด',
9 => 'เก้า',
];
private const THAI_UNITS = [
1 => 'สิบ',
2 => 'ร้อย',
3 => 'พัน',
4 => 'หมื่น',
5 => 'แสน',
6 => 'ล้าน',
];
private const THAI_COMPOUND_ONE = 'เอ็ด';
private const THAI_COMPOUND_TWO = 'ยี่';
private const THAI_INTEGER = 'ถ้วน';
private const THAI_MINUS = 'ลบ';
private const THAI_BAHT = 'บาท';
private const THAI_SATANG = 'สตางค์';
/**
* BAHTTEXT.
*
* @param mixed $number The number or array of numbers to convert
*
* @return array<mixed>|string If an array of values is passed as the argument, then the returned result will also be an array with the same dimensions
*/
public static function getBahtText(mixed $number): array|string
{
if (is_array($number)) {
return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
}
if (is_string($number) && preg_match('/^-?\d+$/', $number)) {
$isNegative = str_starts_with($number, '-');
$baht = ltrim($number, '-0') ?: '0';
$satang = '00';
} elseif (is_bool($number) || is_numeric($number)) {
$number += 0;
$isNegative = $number < 0;
[$baht, $satang] = explode('.', number_format(abs($number), 2, '.', ''));
} else {
return ExcelError::VALUE();
}
$hasWhole = $baht !== '0';
$hasFraction = $satang !== '00';
if (!$hasWhole && !$hasFraction) {
return self::THAI_DIGITS[0] . self::THAI_BAHT . self::THAI_INTEGER;
}
$text = $isNegative
? self::THAI_MINUS
: '';
if ($hasWhole) {
$text .= self::convertLarge($baht) . self::THAI_BAHT;
}
$text .= $hasFraction
? self::convertBlock($satang) . self::THAI_SATANG
: self::THAI_INTEGER;
return $text;
}
private static function convertLarge(string $digits): string
{
$length = strlen($digits) % 6 ?: 6;
$chunks = [
substr($digits, 0, $length),
...str_split(substr($digits, $length), 6),
];
return implode(
self::THAI_UNITS[6],
array_map(self::convertBlock(...), $chunks)
);
}
private static function convertBlock(string $block): string
{
$out = '';
$length = strlen($block);
$i = 0;
// Hundreds and higher powers
for ($power = $length - 1; $power >= 2; --$power) {
$digit = $block[$i++];
if ($digit !== '0') {
$out .= self::THAI_DIGITS[$digit] . self::THAI_UNITS[$power];
}
}
// Tens
$ten = $length > 1 ? $block[$i++] : '0';
if ($ten !== '0') {
$out .= match ($ten) {
'1' => '',
'2' => self::THAI_COMPOUND_TWO,
default => self::THAI_DIGITS[$ten],
} . self::THAI_UNITS[1];
}
// Ones
$one = $block[$i] ?? '0';
if ($one !== '0') {
$out .= $ten !== '0' && $one === '1'
? self::THAI_COMPOUND_ONE
: self::THAI_DIGITS[$one];
}
return $out;
}
}
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\TextData;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class BahtTest extends TestCase
{
#[\PHPUnit\Framework\Attributes\DataProvider('providerBAHTTEXT')]
public function testBAHTTEXT(mixed $expectedResult, bool|string|float|int $number): void
{
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
if (is_bool($number)) {
$formulaValue = $number ? 'TRUE' : 'FALSE';
} elseif (is_string($number)) {
$formulaValue = '"' . $number . '"';
} else {
$formulaValue = (string) $number;
}
$sheet->getCell('A1')->setValue('=BAHTTEXT(' . $formulaValue . ')');
$result = $sheet->getCell('A1')->getCalculatedValue();
self::assertSame($expectedResult, $result);
$spreadsheet->disconnectWorksheets();
}
public static function providerBAHTTEXT(): array
{
return require 'tests/data/Calculation/TextData/BAHTTEXT.php';
}
}
@@ -0,0 +1,98 @@
<?php
declare(strict_types=1);
return [
[
'ศูนย์บาทถ้วน',
0,
],
[
'หนึ่งบาทถ้วน',
1,
],
[
'สองบาทถ้วน',
2,
],
[
'สิบบาทถ้วน',
10,
],
[
'สิบเอ็ดบาทถ้วน',
11,
],
[
'ยี่สิบเอ็ดบาทถ้วน',
21,
],
[
'สี่สิบสองบาทถ้วน',
42,
],
[
'หนึ่งร้อยบาทถ้วน',
100,
],
[
'หนึ่งพันบาทถ้วน',
1000,
],
[
'หนึ่งพันแปดร้อยแปดสิบเจ็ดบาทถ้วน',
1887,
],
[
'ห้าสิบสตางค์',
0.50,
],
[
'หนึ่งบาทยี่สิบห้าสตางค์',
1.25,
],
[
'หนึ่งร้อยยี่สิบสามบาทสี่สิบห้าสตางค์',
123.45,
],
[
'หนึ่งพันสองร้อยสามสิบสี่บาทห้าสิบหกสตางค์',
1234.56,
],
[
'ลบหนึ่งบาทถ้วน',
-1,
],
[
'ลบสี่สิบสามบาทถ้วน',
-42.999,
],
[
'ลบเก้าสิบเก้าบาทถ้วน',
-99,
],
[
'ลบหนึ่งร้อยยี่สิบสามบาทสี่สิบห้าสตางค์',
-123.45,
],
[
'ลบหนึ่งร้อยยี่สิบสามบาทสี่สิบห้าสตางค์',
'-123.452',
],
[
'เก้าร้อยแปดสิบเจ็ดล้านหกแสนห้าหมื่นสี่พันสามร้อยยี่สิบเอ็ดล้านเก้าแสนแปดหมื่นเจ็ดพันหกร้อยห้าสิบสี่ล้านสามแสนสองหมื่นหนึ่งพันเก้าร้อยแปดสิบเจ็ดล้านหกแสนห้าหมื่นสี่พันสามร้อยยี่สิบเอ็ดบาทถ้วน',
'987654321987654321987654321',
],
[
'หนึ่งบาทถ้วน',
true,
],
[
'ศูนย์บาทถ้วน',
false,
],
[
'#VALUE!',
'ABC',
],
];