MAIN DEFINE s STRING LET s = 'ab€c d' DISPLAY SFMT("s:%1 l:%2 w:%3 number_of_logical_chars:%3", s, length(s), fgl_width(s), number_of_logical_chars(s)) LET s = '123456' DISPLAY SFMT("s:%1 l:%2 w:%3 number_of_logical_chars:%3", s, length(s), fgl_width(s), number_of_logical_chars(s))END MAIN FUNCTION number_of_logical_chars(s STRING) RETURNS INT DEFINE i, l, n INT LET l = s.getLength() LET i = 1 LET n = 0 WHILE i <= l VAR c = s.getCharAt(i) LET i += c.getLength() LET n += 1 END WHILE RETURN nEND FUNCTION
$ FGL_LENGTH_SEMANTICS=BYTE fgl ll1s:ab€c d l:8 w:6 number_of_logical_chars:6s:123456 l:6 w:6 number_of_logical_chars:6$ FGL_LENGTH_SEMANTICS=CHAR fgl ll1s:ab€c d l:6 w:6 number_of_logical_chars:6s:123456 l:6 w:6 number_of_logical_chars:6
MAIN DEFINE s, s2 STRING IF fgl_getenv("FGL_LENGTH_SEMANTICS") == "CHAR" THEN DISPLAY "must not have CHAR length semantics to count bytes" RETURN END IF LET s = "🙁🙂ab£c🙁" LET s2 = cutAtByteLength(s, 14) DISPLAY SFMT("s:%1 slen:%2 s2:%3 s2len:%4", s, length(s), s2, length(s2)) LET s = "🙁🙂x" LET s2 = cutAtByteLength(s, 8) DISPLAY SFMT("s:%1 slen:%2 s2:%3 s2len:%4", s, length(s), s2, length(s2))END MAIN FUNCTION cutAtByteLength(s STRING, maxByteLength INT) RETURNS STRING VAR l = s.getLength() --byte length whole string DISPLAY "source has length:", l VAR i = 1 WHILE i <= l VAR c = s.getCharAt(i) VAR clen = c.getLength() --byte length one char LET i += clen DISPLAY SFMT("i:%1,c:%2,len:%3", i, c, c.getLength()) IF i - 1 > maxByteLength THEN RETURN s.subString(1, i - 1 - clen) END IF END WHILE RETURN sEND FUNCTION
IMPORT utilMAIN DEFINE s, s2,smil1,smil2,pound STRING IF fgl_getenv("FGL_LENGTH_SEMANTICS") == "CHAR" THEN DISPLAY "must not have CHAR length semantics to count bytes" RETURN END IF --smileys need 2 unicode code points (beyond Unicode basic plane) CALL util.JSON.parse('"\\uD83D\\uDE01"',smil1) DISPLAY "smil1:",smil1 CALL util.JSON.parse('"\\uD83D\\uDE02"',smil2) DISPLAY "smil2:",smil2 CALL util.JSON.parse('"\\u00a3"',pound) DISPLAY "pound:",pound LET s = smil1,smil2,"ab",pound,"c",smil1 LET s2 = cutAtByteLength(s, 14) --last smil1 is cut because the byte boundary is inbetween DISPLAY SFMT("s:%1 slen:%2 s2:%3 s2len:%4", s, length(s), s2, length(s2)) LET s = smil1,smil2,"x" LET s2 = cutAtByteLength(s, 8) DISPLAY SFMT("s:%1 slen:%2 s2:%3 s2len:%4", s, length(s), s2, length(s2))END MAIN FUNCTION cutAtByteLength(s STRING, maxByteLength INT) RETURNS STRING VAR l = s.getLength() --byte length whole string DISPLAY sfmt("source:'%1' has length:%2",s,l) VAR i = 1 WHILE i <= l VAR c = s.getCharAt(i) VAR clen = c.getLength() --byte length one char LET i += clen DISPLAY SFMT("i:%1,c:%2,len:%3", i, c, c.getLength()) IF i - 1 > maxByteLength THEN RETURN s.subString(1, i - 1 - clen) END IF END WHILE RETURN sEND FUNCTION