locutus
Version:
Locutus other languages' standard libraries to JavaScript for fun and educational purposes
71 lines (70 loc) • 3.1 kB
JavaScript
import { ini_get } from "../info/ini_get.js";
export function strlen(string) {
// discuss at: https://locutus.io/php/strlen/
// original by: Kevin van Zonneveld (https://kvz.io)
// improved by: Sakimori
// improved by: Kevin van Zonneveld (https://kvz.io)
// input by: Kirk Strobeck
// bugfixed by: Onno Marsman (https://twitter.com/onnomarsman)
// revised by: Brett Zamir (https://brett-zamir.me)
// note 1: May look like overkill, but in order to be truly faithful to handling all Unicode
// note 1: characters and to this function in PHP which does not count the number of bytes
// note 1: but counts the number of characters, something like this is really necessary.
// example 1: strlen('Kevin van Zonneveld')
// returns 1: 19
// example 2: ini_set('unicode.semantics', 'on')
// example 2: strlen('A\ud87e\udc04Z')
// returns 2: 3
if (typeof string === 'undefined') {
throw new Error('strlen() expects exactly 1 argument, 0 given');
}
const str = string + '';
const iniVal = ini_get('unicode.semantics') || 'off';
if (iniVal === 'off') {
return str.length;
}
let i = 0;
let lgth = 0;
const getWholeChar = function (str, i) {
const code = str.charCodeAt(i);
if (code >= 0xd800 && code <= 0xdbff) {
// High surrogate (could change last hex to 0xDB7F to
// treat high private surrogates as single characters)
if (str.length <= i + 1) {
throw new Error('High surrogate without following low surrogate');
}
const next = str.charCodeAt(i + 1);
if (next < 0xdc00 || next > 0xdfff) {
throw new Error('High surrogate without following low surrogate');
}
return str.charAt(i) + str.charAt(i + 1);
}
else if (code >= 0xdc00 && code <= 0xdfff) {
// Low surrogate
if (i === 0) {
throw new Error('Low surrogate without preceding high surrogate');
}
const prev = str.charCodeAt(i - 1);
if (prev < 0xd800 || prev > 0xdbff) {
// (could change last hex to 0xDB7F to treat high private surrogates
// as single characters)
throw new Error('Low surrogate without preceding high surrogate');
}
// We can pass over low surrogates now as the second
// component in a pair which we have already processed
return false;
}
return str.charAt(i);
};
for (i = 0, lgth = 0; i < str.length; i++) {
if (getWholeChar(str, i) === false) {
continue;
}
// Adapt this line at the top of any loop, passing in the whole string and
// the current iteration and returning a variable to represent the individual character;
// purpose is to treat the first part of a surrogate pair as the whole character and then
// ignore the second part
lgth++;
}
return lgth;
}