Define mappings for alphanumeric codes using expressions
A naxp (‘encoded ASCII expression’) uses a regex-like syntax to define how ASCII strings should be mapped to a numerical index.
With one simple expression you can standardise conversion of alphanumeric codes to integer indexes unambiguously and consistently across multiple coding languages and hardware platforms.
Examples
| Name | naxp | Encoded values | Bits |
|---|---|---|---|
Flight designatore.g. AC861 |
(\A\A|\A\9|\9\A)
#[0!0!0!1-9999]
|
12 m | 24 |
UK postcodee.g. EC4M 8AD |
\A\A?\9\X? \s!! \9\A\A
|
GIR \s!! 0AA
|
1.8 bn | 31 |
Ireland Eircodee.g. A65 F4E2 |
[AC-FHKNPRTV-Y]
|
1.5 bn | 31 |
Netherlands postcodee.g. 1012 AB |
\9\9\9\9 \s!! \A\A |
6.8 m | 23 |
Get started
Grab a standard naxp
Check if a pre-written standard naxp already exists for your use case.
Standard naxpsDevelop a naxp
Test, debug or develop a naxp interactively, with optional custom code generation.
Interactive naxp designEmbed a naxp
General naxp functionality is available in multiple programming languages.
Find a naxp packageA quick tour
A naxp maps all valid text to a range of consecutive integers starting at 1, and all invalid text to 0.
If two naxps accept the same text and print it the same way then they will produce exactly the same encoded values (and have exactly the same performance).
Characters
Printable ASCII characters are represented as themselves, apart from the following eighteen, which must be escaped with a preceding backslash:
-
thirteen with a special meaning in a naxp,
!#(),-?[\]{|}, and -
five that have a special meaning in a regex but not in a naxp,
*+.^$, which require escaping so that regex users get errors rather than expecting them to work the same way.
Unlike regex, whitespace is always ignored,
so feel free to use spaces to make the expression readable.
If you want the space character to be part of a naxp
then use \s.
A | the character A |
\- | a hyphen (because - is one of the characters that needs to be escaped) |
\s | a space |
Examples: A\-Z and A \- Z
both match A-Z.
Common character set shorthand
Some character sets occur again and again, so naxp has special notation for five of these:
\9 | a digit, i.e. 0 to 9 |
\A | an uppercase letter, i.e. A to Z |
\a | a lowercase letter, i.e. a to z |
\X | a digit or an uppercase letter |
\x | a digit or a lowercase letter |
Example: \A\A\9 matches EC4.
General character sets
Square brackets match any of the items inside them. An item in this context is a single character, an inclusive character range written lowest first, or one of the above character set shorthands.
[AEIOU] | one of A, E, I, O or U |
[A-F] | one of the inclusive range A to F |
[\9A-F] | an uppercase hexadecimal digit |
Example: [\9A-F][\9A-F] matches two-digit hexadecimals from 00 to FF.
Options, groups and alternatives
A question mark ? makes the preceding item optional.
The ? operator binds very tightly,
which means that if you want to apply it to more than one item as a group you need to
put that group in parentheses ().
Tip
In a regex you use ?
to indicate optional text, but a naxp needs to know
whether the different possible text values should be encoded differently or not.
If you want different encodings then use ?.
For instance, a spreadsheet column
could be \A?\A, which is correct because
A and AA are different columns.
But if you want to indicate an optional character that doesn’t change meaning,
e.g. an optional separator in a postcode
then you want the
!! and !? operators.
Vertical bar | separates alternatives.
The | operator binds very loosely,
which means you don’t need parentheses
unless the alternatives themselves are complex expressions.
x? | Optional x |
ABC|XYZ | either ABC or XYZ |
(ABC) | ABC as a group |
Example: \A\A?\9\X? and (\A\A|\A)\9\X?
are equivalent, and both match B1 and EC4M.
Intervals
An interval, represented using braces {}, repeats one item a fixed number of times, or a range of
times. (This is the same syntax as regex, except there is no unbounded form, because a naxp must have a finite
count of values.)
x{3} | exactly three of x |
x{2,4} | two to four of x |
Example: \A{3} matches LHR but not GB,
whereas \A{2,3} matches both.
Variable formats – the ! operator
Sometimes you want to handle variations in text formats that don’t affect meaning. Examples are leading digits in numerical parts of codes, and separators that are not strictly required but often included for readability.
naxp handles this using the binary
‘text unification’ ! operator:
- The expression on the left matches as usual, but is ignored for encoding purposes.
-
The text on the right is the canonical text to replace it with
when mapping an encoded value back to text. The canonical text must be a single fixed string and
included in the possible matches for the expression on the left of the
!.
x!y |
anything x matches, printed as y,
which must be a constant and included in the text that x matches
|
Example: \X [\s\-]!\- \9 matches a capital letter and a digit
separated by a space or a hyphen, but the version with a hyphen is preferred.
So A 1 and A-1 have the same encoded value,
but print as A-1.
Note This is a handy feature but, if you use the text unification operator, it is possible for two naxps to accept the same text but encode it differently. This can happen when they produce different canonical versions for the same accepted text (because it is the canonical text that drives the encoding).
Variable format shortcuts – the !! and !? operators
There are two specialised unary versions of the ‘text unification’ ! operator
for optional text:
x!! |
optional x, canonical text includes x.
|
x!? |
optional x, canonical text excludes x.
|
Tip
The x in x!! must be a single fixed string
– if it’s not then use the binary
! operator.
Example: \A\9\A \s!!\9\A\9 matches Canadian postal codes,
e.g. H0H 0H0, which officially should have a space as the fourth character.
But it will also tolerate a missing space, e.g. H0H0H0, while
(a) giving the same encoding and
(b) printing correctly with the space.
Case sensitivity
The \C and \c operators make
everything that follows them, to the end of the enclosing group,
insensitive to case,
respectively treating upper case and lower case as canonical.
A case fold runs to the end of the group it is written in, like a flag in a regex,
so writing \C at the front of a whole naxp
is the usual way to make it case tolerant.
To fold only part of a naxp, put the fold in parentheses:
(\CA)B folds the A alone.
\Cx |
x in either case, canonical text is upper case |
\cx |
x in either case, canonical text is lower case |
Example: \C \A\A?\9\X? \s \9\A\A matches
a UK postcode regardless of capitalisation.
So ec1a 1bb and EC1A 1BB have the same encoded
value, and that encoded value prints as EC1A 1BB.
Decimal ranges
Alphanumeric code systems often incorporate decimal numbers and
so naxp has a special ‘decimal range’ syntax for this.
The syntax is #[a-b], where
a and b are the digits representing the
lowest and highest values in the range.
Handling leading zeros in numeric text is a perennially thorny issue for alphanumeric codes, so naxp has strong capabilities for handling them. There are four options:
- Exclude leading zeros by omitting them, e.g.
#[1-999]. - Require leading zeros by including them, e.g.
#[001-999]. -
Make leading zeros optional but non-canonical using
0?, e.g.#[0?0?1-999]reprints1,01and001as1. -
Make leading zeros optional and canonical using
0!, e.g.#[0!0!1-999]reprints1,01and001as001.
#[1-9999] | 1 to 9999, one to four digits and no leading zeros |
#[01-31] | 01 to 31, always two digits, with a leading zero where needed |
#[0?0?0-105] |
0 to 105, accepts leading zeros,
canonical text excludes leading zeros |
#[0!0!0-105] |
0 to 105, accepts leading zeros,
canonical text includes leading zeros |
Example: (\A\A|\A\9|\9\A)#[0!0!0!1-9999] matches AC861 but reprints it as AC0861.
Tip
If the canonical form fully uses leading zeros (e.g.
#[001-999] or #[0!0!1-999],
but not #[1-999] or #[0?0?1-999])
then the encoded values sort in the same order as the numbers they represent.
Operator precedence
From loosest to tightest binding, so an operator lower in the table applies before one above it.
Use parentheses () to override the order, as in a regex.
\C \c | everything to the end of the enclosing group: \CA|b is \C(A|b) |
| | alternatives: AB|CD is (AB)|(CD) |
| concatenation | one element after another: A?B is (A?)B |
! !! !? | an element with its quantifier: A?!() is (A?)!() |
? {} | a single element: AB? is A(B?) |
Computational constraints
All naxps define a maximum length for the text they accept. (In comparison, some regexes accept arbitrarily long text.)
For some complex naxps, it is possible for the computations required to get very large. To ensure consistent behaviour across platforms, the constraints on these computations are defined in the specification.
Further reading
For more information, see: