Lodash - strings
About
These functions dramatically simplify working with strings in 4D. Many of them are ported from JavaScript; others provide more convenient ways to use 4D’s built-in string commands.
API
.capitalize()
.capitalize(str : Text { ; lowercase : Boolean }) : Text
Uppercases the first letter of str. If lowercase is true, the remainder of str is lowercased.
.convertLineBreaks()
.convertLineBreaks(text : Text { ; breakMode : Integer }) : Text
.convertLineBreaks(text : Text { ; breakMode : Text }) : Text
Converts line breaks in text according to the value of breakMode, which may be one of the break mode values documented in the 4D File.open
function.
If breakMode is invalid, the function returns text unchanged.
NOTE
On macOS, Document with native format
in this function always means LF
(not CR
).
.decodeURIComponent()
.decodeURIComponent(str : Text) : Text
Replaces each %XX
escape sequence in str with the UTF-8 character it represents.
Example
$decoded:=_.decodeURIComponent("https%3A%2F%2Fwww.example.com%2F%3Fq%3D4D")
// => https://www.example.com/?q=4D
.description()
.description(value : any { ; pretty : Boolean { ; indent : Text }}) : Text
Intelligently converts value to a debug representation of a value:
If value is an instance of a built-in 4D class (e.g.
4D.Entity
), its class and essential properties are returned prettified.If value is undefined, "<undefined>" is returned.
If value is an object and has a
.description
property which is a function, the function is called. This allows you to define a debug representation of instances of your own classes.If value is a collection, the result of calling
_.description()
for each element of the collection is returned if it is non-null, otherwise "null" is returned.If value is a variable pointer, the name of the variable and its value is returned. If value points to an array, the contents of the array are returned.
If value is a table/field pointer, the name of the table and field is returned.
If value is a picture, the picture’s dimensions and byte size are returned.
Otherwise if value is an object, it is stringified with the pretty flag.
For all other types, the result of
_.toString(value)
is returned.
For types that are prettified, if indent is not empty, it is used to replace the leading tab characters on each line in the result.
TIP
If you want a user-facing representation of a class, define .toString()
. If you want a debug representation of a class, define .description()
. If one representation will suffice, just define .toString()
, as _.description()
falls back to that for user classes.
.encodeURIComponent()
.encodeURIComponent(str : Text) : Text
An implementation of the JavaScript .encodeURIComponent()
function. All characters except these are encoded:
A-Z a-z 0-9 - _ . ! ~ * ' ( )
Example
$encoded:=_.encodeURIComponent("https://www.example.com/?q=4D")
// => https%3A%2F%2Fwww.example.com%2F%3Fq%3D4D
.format()
.format(template : Text; value : any { ; …valueN : any }) : Text
Formats template using the supplied values. The template may contain placeholders which will be replaced by the values. Placeholders are in the form:
${<index>|<index>.<key path>|<key path>}
<index>
is the one-based index of the value in the list of values passed to the function (starting with value).<key path>
is a dot-separated path in the format used by_.valueForKeyPath()
. Thus it may refer to object properties and/or collection elements.If the placeholder does not have an
<index>
, it is assumed to be 1.
Numeric indexes do not need to be in ascending order from left to right in template. Any placeholder may be used more than once in the template.
Placeholders may also contain a format, separated from the index or property path by |
. All values are passed to .toString()
along with the format (if any) before replacing the corresponding placeholders. Undefined values are replaced with an empty string.
Examples
$s:=_.format("The time is ${1|time} on ${2}"; Current time; Current date)
// => "The time is 08:27:31 on 04/13/22"
$s:=_.format(\
"Hi ${name}! We have your age as ${age}. Is that correct, ${name}?"; \
New object("name"; "Homer"; "age"; 27))
// => "Hi Homer! We have your age as 27. Is that correct, Homer?"
$s:=_.format("Date: ${1|9}"; Current date) // 9 = ISO Date GMT
// => "Date: 2010-09-13T16:11:53Z"
$s:=_.format("Amount: $${1|###,###,##0.00;(###,###,##0.00);0}"; $amount)
// => $amount = 13.27: "Amount $13.27"
// => $amount = -31: "Amount: $(-31.00)"
// => $amount = 0: "Amount: $0"
$homer:=_.json("{ 'name': 'Homer', 'addresses': [{ 'street': '113 Main St', 'city': 'Springfield', 'state': 'MO' }]}")
$s:=_.format("Hi ${name}, how are things in ${addresses.[0].city}?"; $homer)
// => "Hi Homer, how are things in Springfield?"
// Format a collection, * means pretty-print
$s:=_.format("${1|*}"; $collection)
// Use a localized date format
$user:=New object("name"; "Homer")
$s:=_.format("Hi ${name}, your next appointment is ${1|LLL}"; $user; DateTime.now())
.formatBytes()
.formatBytes(number : Real { ; …decimal : Boolean }) : Text
Formats number with a unit suffix: bytes | KB | MB | GB | TB | PB
The breakpoint for the units depends on decimal. If decimal is false (the default), the breakpoints between units are powers of 1024. Otherwise they are powers of 1000.
Examples
$bytes:=_.formatBytes(1024*1.5) // 1536
// => "1.5 KB"
$bytes:=_.formatBytes(1024*1.5; True) // 1536
// => "1.54 KB"
.hexEncode()
.hexEncode(blob : Blob; { ; lowercase : Boolean }) : Text
Returns the bytes in blob as a series of hex numbers. If lowercase is true, the hex numbers are lowercase.
Example
var $blob: Blob
CONVERT FROM TEXT("☮️ Привіт"; "utf-8"; $blob) // Ukrainian for "Hi"
$encoded:=_.hexEncode($blob; True)
// => "e298aeefb88f20d09fd180d0b8d0b2d196d182"
.hexToDecimal()
.hexToDecimal(chars : Text) : Integer
Converts hex digits (uppercase or lowercase) to decimal.
If chars is an empty string, zero is returned. If chars contains invalid hex digits, -1 is returned. If chars has an odd length, it is prefixed with a leading zero before being converted.
Examples
$decimal:=_.hexToDecimal("")
// => 0
$decimal:=_.hexToDecimal("d")
// => 13
$decimal:=_.hexToDecimal("abc1234")
// => 180097588
$decimal:=_.hexToDecimal("abz1234")
// => -1
.httpEncodeUnicode()
.httpEncodeUnicode(str : Text) : Text
Encodes a Unicode string for HTTP (RFC 5987).
Example
$encoded:=_.httpEncodeUnicode("😁 (grin)")
// => "UTF-8''%F0%9F%98%81%20%28grin%29"
.httpQuote()
.httpQuote(str : Text) : Text
Quotes a string for HTTP. Backslashes and double quotes are escaped, and then the result is enclosed in double quotes.
Example
$quoted:=_.httpQuote("A \"file\"")
// => "A \\"file\\""
.json()
.json(json : Text) : any
Converts a textual representation of a JSON value, which is way easier to type (but of course slower to execute) than using New object
when you have a complex object or New collection
when you have a complex collection.
json should be in the same format as JSON, but using single quotes instead of double quotes. This makes it easy to write a literal JSON string in 4D without having to constantly backslash the double quotes around property names. To include a single quote within a string value, prefix it with \
.
If json is malformed, undefined is returned and _.lastError
will be set.
Examples
$object:=_.json("{ 'foo': 'bar', 'boo': { 'baz': ['Can\\'t touch this', 7, null], 'bool': true }}")
$collection:=_.json("[ 'foo', 'bar', 7, { 'baz': null }]")
.lastPosition()
.lastPosition(find : Text; str : Text { ; start : Integer { ; characterCodes : Boolean }}) : Integer
Like Position()
, but finds the last occurrence of find in str. start is the last character in str (working backwards towards the start of the string) that can be considered the start of a match.
If start is not passed or is >= Length(str)
, the whole string is searched. If start < 1, it is pinned to 1.
Examples
$pos:=_.lastPosition("foo"; "foobarbazfoo")
// => 10
$pos:=_.lastPosition("foo"; "foobarbazfoo"; MAXLONG)
// => 10
$pos:=_.lastPosition("foo"; "foobarbazfoo"; -1)
// => 1
$pos:=_.lastPosition("foo"; "foobarbazfoo"; 9)
// => 1
.match()
.match(str1 : Text; str2 : Text) : Boolean
Returns whether two strings match exactly by comparing them using the sk strict
mode of Compare strings
.
NOTE
@
is not considered a wildcard.
.padEnd()
.padEnd(str : Text; targetLength : Integer { ; padStr : Text }) : Boolean
An implementation of JavaScript’s String.padEnd()
. Pads str with another string (multiple times, if needed) until the resulting string reaches targetLength. The padding is applied from the end of str.
If targetLength is less than Length(str)
, then str is returned as-is.
If padStr is too long to stay within targetLength, it will be truncated from the start. The default value of padStr is the Unicode space character.
Examples
// add space at the end if targetLength > length(str)
_.padEnd("foo"; 7) // => "foo "
// add no space if targetLength <= length(str)
_.padEnd("foo"; 2) // => "foo"
// repeat the complete filler and truncate it to targetLength
_.padEnd("foo"; 7; "bar") // => "foobarb"
.padStart()
.padStart(str : Text; targetLength : Integer { ; padStr : Text }) : Boolean
An implementation of JavaScript’s String.padStart()
. Pads str with another string (multiple times, if needed) until the resulting string reaches targetLength. The padding is applied from the start of str.
If targetLength is less than Length(str)
, then str is returned as-is.
If padStr is too long to stay within targetLength, it will be truncated from the end. The default value of padStr is the Unicode space character.
Examples
// add space at the start if targetLength > length(str)
_.padStart("foo"; 7) // => " foo"
// add no space if targetLength <= length(str)
_.padStart("foo"; 2) // => "foo"
// repeat the complete filler and truncate it to targetLength
_.padStart("foo"; 7; "bar") // => "barbfoo"
.parseBytes()
.parseBytes(str : Text { ; decimal : Boolean }) : Integer | Null
Parses str into an integer expressed in bytes. If no unit is given in str, it is assumed the value is in bytes. The number may have a leading sign.
Supported units (case-insensitive) are: B | K | KB | MB | GB | TB | PB
. There may be one or more spaces between the number and the unit. If an invalid unit is specified, null is returned.
By default, this function parses in binary mode: 1K = 1024. If decimal is true, then 1K = 1000.
Examples
_.parseBytes("1327") // => 1327
_.parseBytes("13K") // => 13312
_.parseBytes("13 KB") // => 13312
_.parseBytes("13 KB"; True) // => 13000
_.parseBytes("13 BB") // => null
.parseJSON()
.parseJSON(json : Text { ; type : Integer { ; markResult : Boolean }}) : any
A wrapper around JSON Parse
that returns an instance of cs.js.SyntaxError
if json is malformed.
If markResult is true, then JSON Parse(json; type; *)
is called.
Examples
$object:=_.parseJSON("{")
If (Not(_.instanceOf($object; cs.js.SyntaxError)))
// valid JSON
Else
// handle error
End if
.prettify()
.prettify(value : any { ; indent : Text) : Text
A convenience function that calls .stringify(value; True; indent)
.
.stringify()
.stringify(value : any { ; pretty : Boolean { ; indent : Text }}) : Text
This is a more intelligent version of JSON Stringify()
. If pretty is true, it is the equivalent of calling JSON Stringify(value; *)
. The tab indents 4D uses are replaced with 4 spaces or indent (if not empty).
If value is undefined, "<undefined>"
is returned.
If value is a cyclic object, no error is thrown. If it responds to .toString()
, the result of that function is returned. Otherwise, "Cyclic instance of <class>"
is returned.
If value is a collection and any of its elements are cyclic objects, they are replaced as described above for cyclic objects.
IF value is a type that cannot be stringified (e.g. a picture), a TypeError
error is thrown.
.toString()
.toString(value : any { ; format : Text | Integer }) : Text
Works like String()
but with some extra functionality beyond String()
.
If value is an object and responds to .toString()
, the function is called with This
= value and format as a parameter. This lets you define a standard way to present instances of your own classes as strings.
TIP
If you want a user-facing representation of a class, define .toString()
. If you want a debug representation of a class, define .description()
. If one representation will suffice, just define .toString()
, as _.description()
falls back to that for user classes.
WARNING
If value is a cyclic object, its .toString()
function must NOT call _.stringify()
or an infinite loop will occur!
Otherwise, if value is an object or collection, it is stringified via .stringify()
, and if format is "*", pretty is true.
If value is a Blob
or 4D.Blob
, format must be supplied to convert it to text. If format is a number or text consisting of all digits, it should be a valid numeric textFormat
constant that would be passed to BLOB to text()
. If format is text and not all digits, it should be a character set name that will be passed to Convert to text()
.
Since 4D sometimes internally converts Time
values into numbers, to ensure Time
values are formatted as times, you can specify a format of "time". If you want to use a numeric time format other than the default, prefix it with "time:" and append the numeric value (not the name) of a time formatting constant.
For numeric values, format may be any valid text format that may be used with String()
, for example "$###,###,###.00"
.
For dates or times, format may be the numeric value (not the name) of a date or time formatting constant.
Examples
$str:="Liberté, égalité, fraternité"
CONVERT FROM TEXT($str; "utf-8"; $blob)
_.toString($blob; "utf-8")=$str // => True
_.toString($blob; UTF8 text without length)=$str // True
_.toString(Current time; "time:5") // => "7:13 PM"
.trim()
.trim(str : Text { ; charsToTrim : Text }) : Text
Trims characters from the start and end of str.
If charsToTrim is passed and is non-empty, it represents the set of characters to trim. Note that charsToTrim is treated as a regular expression character set, so the placement of "-" within it is significant, and "^" at the beginning does a reverse match. If charsToTrim is not passed or is empty, whitespace ("\s", which includes tabs and line terminators) is trimmed.
Examples
$str:="\n\t Test \n"
_.trim($str) // => "Test"
_.trim($str; "\n") // => "\t Test "
_.trim("(foo)\n"; "\n()") // => "foo"
.trimEnd()
.trimEnd(str : Text { ; charsToTrim : Text }) : Text
Trims characters from the end of str. For more information, see trim().
.trimStart()
.trimStart(str : Text { ; charsToTrim : Text }) : Text
Trims characters from the end of str. For more information, see trim().