Strings and Regular Expressions

Karl Falconer ·

BGL has limited string functions but powerful pattern matching. Almost everything you’d want to do to a string — extract part of it, test its shape, replace something — uses a regular expression.

when order.id matches /^EXT-\d+$/ then
  set order.custom.tag to "external"
end

Reads as: when the order’s id matches the pattern “EXT-“ followed by digits, tag it as external.

If you’ve never used regex before, the regex cheat sheet at the bottom covers the common building blocks.

Concatenation

Use & to glue strings together:

"Order: " & order.id & " (" & order.status & ")"
order.shipping_address.first_name & " " & order.shipping_address.last_name

Both sides of & must be text. To concatenate a number, cast it first:

"Total: $" & order.subtotal as text

Matching a pattern

The matches operator tests whether a string fits a regex:

when order.id matches /^[A-Z]{3}\d+$/ then ... end
when order.customer_email matches /@example\.com$/ then ... end
when order_line.sku matches /^HAZMAT-/ then ... end

Regex literals are slash-delimited: /pattern/. Inside, you can use any standard regex syntax.

Extracting a piece with named captures

To pull a piece out of a string, use a named capture inside a regex and bind it to a variable using the pipe (|) syntax:

prefix | /^(?<prefix>[A-Z]+)-/ matches order.id

Reads as: match order.id against this pattern, and bind the named group prefix to a variable called prefix.

Once captured, the variable is available wherever an expression can go:

set order.custom.tag to prefix | /^(?<prefix>[A-Z]+)-/ matches order.id

A common pattern: extract on one line, use on the next.

set order.custom.normalized_id to num | /(?<num>\d+)/ matches order.external_id

Replacing text

The replace action substitutes one piece of text for another, using a regex to find it:

set order.id to replace /_/ with "-" in order.id
set order.notes to replace /\s+/ with " " in order.notes

The pattern is replace /pattern/ with "replacement" in <text>. The replacement is a literal string (not another regex).

To use a captured value in the replacement, work with named captures and a session variable:

set $part to part | /^(?<part>\w+)/ matches order.id
set order.custom.normalized to replace /^\w+/ with $part in order.custom.normalized

Iterating regex matches

For every match in a string — not just the first — use the regex form of for:

for /(?<num>\d+)/ in order.notes
  print "Found number: " & num
end

Each iteration sets the named capture (here num) to the matched substring.

This is the only way to “split” a string in BGL. To split on a delimiter, capture the non-delimiter parts:

for /(?<part>[^,]+)/ in order.custom.tags
  # `part` is each comma-separated value
end

What you cannot do directly

BGL doesn’t have these common string functions, so you’ll work around them with regex:

Want to… Workaround
Get the length Often unnecessary — match against a length-bounded pattern with matches /^.{N}$/.
Trim whitespace replace /^\s+/ with "" in field then replace /\s+$/ with ""
Uppercase / lowercase Not supported. Use case-insensitive regex with (?i).
Substring (positions) Capture the segment with regex: prefix \| /^(?<prefix>.{5})/ matches field.
Split on delimiter Loop with for /(?<part>[^,]+)/ in field.

If a workaround is awkward, consider whether the source data could be normalized upstream — sometimes “fix it before it gets to us” is easier than fixing it in a rule.

Regex cheat sheet

Pattern Matches
abc The literal text “abc”
^abc “abc” at the start of the string
abc$ “abc” at the end of the string
\d A digit (0-9)
\w A word character (letter, digit, or _)
\s Whitespace
. Any single character (except newline)
[abc] Any one of a, b, or c
[^abc] Anything except a, b, or c
[a-z] Lowercase letter
* Zero or more of the preceding
+ One or more of the preceding
? Zero or one of the preceding
{n} Exactly n
{n,m} Between n and m
(...) Group
(?<name>...) Named capture group
\| Either side
\., \\, \/, etc. Literal ., \, /

A few useful complete patterns:

Pattern Matches
/^\d+$/ A whole string of digits
/^[A-Z]{3}\d+$/ 3 capital letters then any number of digits
/^.+@.+\..+$/ A loose email pattern (better one in the snippets reference)
/^[A-Z]{2}$/ Two-letter state or country code

For more, see your favorite regex reference — Mozilla’s MDN regex docs are good — and test patterns at https://regex101.com/ before pasting them into a rule.

Built-in regex snippets

The code editor ships with snippets for common regex patterns: numbers, n-digit minimums, state-code lists, character repetition, email, phone. Type matches in the code editor and pick from the autocomplete list. See Snippets Reference.

Was this article helpful?
0 out of 0 found this helpful

Comments

0 comments

Please sign in to leave a comment.