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.openopen in new window 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()open in new window 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)open in new window.

Example

$encoded:=_.httpEncodeUnicode("😁 (grin)")
// => "UTF-8''%F0%9F%98%81%20%28grin%29"

.httpQuote()

.httpQuote(str : Text) : Text

Quotes a string for HTTPopen in new window. 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()open in new window, 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 stringsopen in new window.

NOTE

@ is not considered a wildcard.


.padEnd()

.padEnd(str : Text; targetLength : Integer { ; padStr : Text }) : Boolean

An implementation of JavaScript’s String.padEnd()open in new window. 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()open in new window. 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()open in new window. 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()open in new window 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()open in new window. If format is text and not all digits, it should be a character set name that will be passed to Convert to text()open in new window.

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 setopen in new window, 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().

Last Updated:
Contributors: Aparajita