Merge pull request #21575 from agh1/5.42.0-releasenotes-initial
[civicrm-core.git] / CRM / Utils / EnglishNumber.php
CommitLineData
0ae8b1af
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
0ae8b1af 5 | |
bc77d7c0
TO
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
0ae8b1af
TO
9 +--------------------------------------------------------------------+
10 */
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
0ae8b1af
TO
16 * Utilities for rendering numbers as English.
17 *
18 * Note: This file may be used in a standalone environment. Please ensure it
19 * remains self-sufficient (without needing any external services).
20 */
21class CRM_Utils_EnglishNumber {
22
be2fb01f 23 protected static $lowNumbers = [
0ae8b1af
TO
24 'Zero',
25 'One',
26 'Two',
27 'Three',
28 'Four',
29 'Five',
30 'Six',
31 'Seven',
32 'Eight',
33 'Nine',
34 'Ten',
35 'Eleven',
36 'Twelve',
37 'Thirteen',
38 'Fourteen',
39 'Fifteen',
40 'Sixteen',
41 'Seventeen',
42 'Eighteen',
43 'Nineteen',
be2fb01f 44 ];
0ae8b1af 45
be2fb01f 46 protected static $intervalsOfTen = [
0ae8b1af
TO
47 9 => 'Ninety',
48 8 => 'Eighty',
49 7 => 'Seventy',
50 6 => 'Sixty',
51 5 => 'Fifty',
52 4 => 'Forty',
53 3 => 'Thirty',
54 2 => 'Twenty',
be2fb01f 55 ];
0ae8b1af
TO
56
57 /**
58 * @param int $num
59 * Ex: 12 or 54.
60 * @param mixed $default
61 * The default value to return if we cannot determine an English representation.
62 * If omitted or NULL, throws an exception.
63 * Tip: If you want to support high values as numerals, just pass the number again.
64 * @return string
65 * Ex: 'Twelve' or 'FiftyFour'.
66 */
67 public static function toCamelCase($num, $default = NULL) {
68 if (isset(self::$lowNumbers[$num])) {
69 return self::$lowNumbers[$num];
70 }
71
72 $tens = (int) ($num / 10);
73 $last = $num % 10;
74 if (isset(self::$intervalsOfTen[$tens])) {
75 if ($last == 0) {
76 return self::$intervalsOfTen[$tens];
77 }
78 else {
79 return self::$intervalsOfTen[$tens] . self::$lowNumbers[$last];
80 }
81 }
82
83 if ($default === NULL) {
84 throw new \RuntimeException("Cannot convert number to English: " . (int) $num);
85 }
86 else {
87 return $default;
88 }
89 }
90
91 /**
92 * @param int $num
93 * Ex: 12 or 54.
94 * @param mixed $default
95 * The default value to return if we cannot determine an English representation.
96 * If omitted or NULL, throws an exception.
97 * Tip: If you want to support high values as numerals, just pass the number again.
98 * @return string
99 * Ex: 'twelve' or 'fifty-four'.
100 */
101 public static function toHyphen($num, $default = NULL) {
102 if (isset(self::$lowNumbers[$num])) {
103 return strtolower(self::$lowNumbers[$num]);
104 }
105
106 $tens = (int) ($num / 10);
107 $last = $num % 10;
108 if (isset(self::$intervalsOfTen[$tens])) {
109 if ($last == 0) {
110 return strtolower(self::$intervalsOfTen[$tens]);
111 }
112 else {
113 return strtolower(self::$intervalsOfTen[$tens]) . '-' . strtolower(self::$lowNumbers[$last]);
114 }
115 }
116
117 if ($default === NULL) {
118 throw new \RuntimeException("Cannot convert number to English: " . (int) $num);
119 }
120 else {
121 return $default;
122 }
123 }
124
91361f52
TO
125 /**
126 * Convert an English-style number to an int.
127 *
128 * @param string $english
129 * Ex: 'TwentyTwo' or 'forty-four'
130 *
131 * @return int
132 * 22 or 44
133 */
134 public static function toInt(string $english) {
135 $intBuf = 0;
136 $strBuf = strtolower(str_replace('-', '', $english));
137
138 foreach (self::$intervalsOfTen as $num => $name) {
139 if (CRM_Utils_String::startsWith($strBuf, strtolower($name))) {
140 $intBuf += 10 * $num;
141 $strBuf = substr($strBuf, strlen($name));
142 break;
143 }
144 }
145 foreach (array_reverse(self::$lowNumbers, TRUE) as $num => $name) {
146 if (CRM_Utils_String::startsWith($strBuf, strtolower($name))) {
147 $intBuf += $num;
148 $strBuf = substr($strBuf, strlen($name));
149 break;
150 }
151 }
152
153 if (!empty($strBuf)) {
154 throw new InvalidArgumentException("Failed to parse english number: $strBuf");
155 }
156
157 return $intBuf;
158 }
159
160 /**
161 * Determine if a string looks like
162 *
163 * @param string $english
164 *
165 * @return bool
166 */
167 public static function isNumeric(string $english): bool {
168 static $pat;
169 if (empty($pat)) {
170 $words = array_map(
171 function($w) {
172 return preg_quote(strtolower($w));
173 },
174 array_merge(array_values(self::$lowNumbers), array_values(self::$intervalsOfTen))
175 );
176 $pat = '/^(\-|' . implode('|', $words) . ')+$/';
177 }
178 return (bool) preg_match($pat, strtolower($english));
179 }
180
0ae8b1af 181}