@@ -1274,6 +1274,111 @@ public static function walkString(string $str): iterable
12741274 }
12751275 }
12761276
1277+ /**
1278+ * Compute string length
1279+ * @param string $str
1280+ * @return int
1281+ * @throws InvalidStringException
1282+ */
1283+ public static function getStringLength (string $ str ): int
1284+ {
1285+ $ count = 0 ;
1286+ $ length = strlen ($ str );
1287+
1288+ $ i = 0 ;
1289+ while ($ i < $ length ) {
1290+ $ ord0 = ord ($ str [$ i ++]);
1291+
1292+ if ($ ord0 < 0x80 ) {
1293+ $ count ++;
1294+ continue ;
1295+ }
1296+
1297+ if ($ i === $ length || $ ord0 < 0xC2 || $ ord0 > 0xF4 ) {
1298+ throw new InvalidStringException ($ str , $ i - 1 );
1299+ }
1300+
1301+ $ ord1 = ord ($ str [$ i ++]);
1302+
1303+ if ($ ord0 < 0xE0 ) {
1304+ if ($ ord1 < 0x80 || $ ord1 >= 0xC0 ) {
1305+ throw new InvalidStringException ($ str , $ i - 1 );
1306+ }
1307+
1308+ // $ord1 = ($ord0 - 0xC0) * 64 + $ord1 - 0x80;
1309+ $ count ++;
1310+
1311+ continue ;
1312+ }
1313+
1314+ if ($ i === $ length ) {
1315+ throw new InvalidStringException ($ str , $ i - 1 );
1316+ }
1317+
1318+ $ ord2 = ord ($ str [$ i ++]);
1319+
1320+ if ($ ord0 < 0xF0 ) {
1321+ if ($ ord0 === 0xE0 ) {
1322+ if ($ ord1 < 0xA0 || $ ord1 >= 0xC0 ) {
1323+ throw new InvalidStringException ($ str , $ i - 2 );
1324+ }
1325+ } elseif ($ ord0 === 0xED ) {
1326+ if ($ ord1 < 0x80 || $ ord1 >= 0xA0 ) {
1327+ throw new InvalidStringException ($ str , $ i - 2 );
1328+ }
1329+ } elseif ($ ord1 < 0x80 || $ ord1 >= 0xC0 ) {
1330+ throw new InvalidStringException ($ str , $ i - 2 );
1331+ }
1332+
1333+ if ($ ord2 < 0x80 || $ ord2 >= 0xC0 ) {
1334+ throw new InvalidStringException ($ str , $ i - 1 );
1335+ }
1336+
1337+ // $ord2 = ($ord0 - 0xE0) * 0x1000 + ($ord1 - 0x80) * 64 + $ord2 - 0x80;
1338+ $ count ++;
1339+
1340+ continue ;
1341+ }
1342+
1343+ if ($ i === $ length ) {
1344+ throw new InvalidStringException ($ str , $ i - 1 );
1345+ }
1346+
1347+ $ ord3 = ord ($ str [$ i ++]);
1348+
1349+ if ($ ord0 < 0xF5 ) {
1350+ if ($ ord0 === 0xF0 ) {
1351+ if ($ ord1 < 0x90 || $ ord1 >= 0xC0 ) {
1352+ throw new InvalidStringException ($ str , $ i - 3 );
1353+ }
1354+ } elseif ($ ord0 === 0xF4 ) {
1355+ if ($ ord1 < 0x80 || $ ord1 >= 0x90 ) {
1356+ throw new InvalidStringException ($ str , $ i - 3 );
1357+ }
1358+ } elseif ($ ord1 < 0x80 || $ ord1 >= 0xC0 ) {
1359+ throw new InvalidStringException ($ str , $ i - 3 );
1360+ }
1361+
1362+ if ($ ord2 < 0x80 || $ ord2 >= 0xC0 ) {
1363+ throw new InvalidStringException ($ str , $ i - 2 );
1364+ }
1365+
1366+ if ($ ord3 < 0x80 || $ ord3 >= 0xC0 ) {
1367+ throw new InvalidStringException ($ str , $ i - 1 );
1368+ }
1369+
1370+ // $ord3 = ($ord0 - 0xF0) * 0x40000 + ($ord1 - 0x80) * 0x1000 + ($ord2 - 0x80) * 64 + $ord3 - 0x80;
1371+ $ count ++;
1372+
1373+ continue ;
1374+ }
1375+
1376+ throw new InvalidStringException ($ str , $ i - 1 );
1377+ }
1378+
1379+ return $ count ;
1380+ }
1381+
12771382 /**
12781383 * Converts each code point to a char
12791384 * @param array $codes
0 commit comments