lexical is a header-only library of validators for the string formats of
JSON Schema, in C++20, one of the libraries of
webcpp. Each format is a function that
takes a std::string_view and answers bool, and, but regex, a Boost.URL
grammar rule, which composes with Boost.URL’s combinators into grammars of a
program’s own. Each is checked as its RFC or ECMA-262 defines it, against
the official JSON-Schema-Test-Suite, and regex against V8. Nothing
allocates but an IRI too long for its inline buffer, through a
std::pmr::memory_resource.
This page teaches lexical format by format: what each checks, its rules and its examples. Every program it shows was compiled and run, natively and for wasm32-wasip2, wasm32-wasip3 and emscripten, and printed the output shown under it. The reference that closes it lists every name the headers declare.
Introduction
JSON Schema names string formats, date-time, email, hostname, uri,
regex and the others, each defined by an RFC or by ECMA-262. lexical checks
each of them as its reference defines it, and nothing more: a validator
answers whether a string is in the format, and a rule says where in a longer
input the format’s text ends.
Every validator takes any byte string. One that is not well-formed UTF-8 is invalid in every format, and in the formats that are ASCII, so is any byte above 0x7F.
| Format | Function | Reference |
|---|---|---|
|
|
RFC 3339 5.6, 5.7 |
|
|
RFC 3339 5.6 |
|
|
RFC 3339 5.6 |
|
|
RFC 3339 appendix A |
|
|
RFC 5321 4.1.2 |
|
|
RFC 6531 3.3 |
|
|
RFC 1123 2.1, RFC 5890 2.3.2.1 |
|
|
RFC 5890 2.3.2.3, UTS 46 |
|
|
RFC 2673 3.2 |
|
|
RFC 4291 2.2 |
|
|
RFC 3986 3 |
|
|
RFC 3986 4.1 |
|
|
RFC 3987 2.2 |
|
|
RFC 3987 2.2 |
|
|
RFC 6570 2 |
|
|
RFC 6901 3 |
|
|
draft-handrews-relative-json-pointer-01 |
|
|
RFC 9562 4 |
|
|
ECMA-262 |
A first example
A program that checks a string of a few formats:
#include <webcpp/lexical.hpp>
#include <iostream>
#include <string_view>
namespace lexical = webcpp::lexical;
namespace {
void show(std::string_view format, std::string_view text, bool valid) {
std::cout << format << ' ' << text << ": " << (valid ? "valid" : "invalid") << '\n';
}
} // namespace
int main() {
show("date-time", "1985-04-12T23:20:50.52Z", lexical::is_date_time("1985-04-12T23:20:50.52Z"));
show("date", "2021-02-29", lexical::is_date("2021-02-29"));
show("email", "joe.bloggs@[IPv6:::1]", lexical::is_email("joe.bloggs@[IPv6:::1]"));
show("hostname", "xn--nxasmq6b.example", lexical::is_hostname("xn--nxasmq6b.example"));
show("uri", "//example.com/p", lexical::is_uri("//example.com/p"));
show("uri-reference", "//example.com/p", lexical::is_uri_reference("//example.com/p"));
show("json-pointer", "/a~1b", lexical::is_json_pointer("/a~1b"));
}
It prints:
date-time 1985-04-12T23:20:50.52Z: valid date 2021-02-29: invalid email joe.bloggs@[IPv6:::1]: valid hostname xn--nxasmq6b.example: valid uri //example.com/p: invalid uri-reference //example.com/p: valid json-pointer /a~1b: valid
2021-02-29 is no date, 2021 being no leap year; //example.com/p is a
URI reference and no URI, which needs a scheme.
Requirements
<webcpp/lexical.hpp> includes every format but regex, whose header
<webcpp/lexical/regex.hpp> brings the Unicode tables of ECMA-262’s classes;
the names are in the namespaces webcpp::lexical and
webcpp::lexical::grammar. lexical is header-only C++20 and needs Boost
1.92 or newer: Boost.URL, whose compiled part webcpp builds from Boost’s
sources for every target, and Boost.System; and webcpp’s configuration,
config, and webcpp::idna, for internationalized names. A b2
project uses it through /webcpp/lexical//lexical, which brings all of
them:
alias lexical
: : : : <include>include <library>/boost//headers
<library>/webcpp/config//config
<library>/webcpp/idna//idna
<library>/webcpp//boost_url ;
It runs natively, on wasm32-wasip2 and wasm32-wasip3, and on emscripten, with exceptions or without.
Dates and times
is_date_time, is_date and is_time check RFC 3339’s date-time,
full-date and full-time (section 5.6), and is_duration its appendix A’s
duration, exactly: ASCII digits only, a month 01 to 12, a day that exists
in its month of the Gregorian calendar (February 29 in a year divisible by 4,
and not by 100 unless by 400), hours 00 to 23, minutes 00 to 59, any number
of fraction digits, and an offset of Z or +hh:mm/-hh:mm. T and Z
match in either case, as RFC 3339’s note says; so do the letters of a
duration, which are ABNF’s quoted strings (RFC 5234 2.3).
Second 60 is a leap second. RFC 3339 allows it when the time, moved to UTC
by its offset, is 23:59, and is_time(s) follows it, as drafts 7 to 2020-12
of JSON Schema test. JSON Schema v1 says a time must not hold one:
is_time(s, leap_seconds::refused) is its time. is_date_time allows them
in every draft, v1 included, as the suite’s date-time tests say. The date
of a leap second is not checked against IERS’s list: no table, the same
answer every year.
A duration’s numbers are never converted, so any number of digits is valid
and nothing overflows. P1Y2D is invalid: appendix A keeps years, months
and days in that order and contiguous, and a week stands alone.
Identifiers
is_uuid checks RFC 9562’s string form of a UUID: 32 hexadecimal digits in
either case, in groups of 8, 4, 4, 4 and 12 joined by hyphens. It checks the
shape, not the version or the variant, as JSON Schema’s suite asks; braces
and the urn:uuid: prefix are not part of the form.
is_json_pointer checks RFC 6901’s JSON Pointer: the empty string, or
reference tokens each led by /, in which ~ is followed by 0 or 1. A
token holds any other code point, NUL included, so the string is decoded as
UTF-8 and must be well-formed.
is_relative_json_pointer checks a relative JSON Pointer: a non-negative
integer without a leading zero, then # or a JSON Pointer. Draft 2020-12 and
v1 of JSON Schema cite draft-bhutton-relative-json-pointer-00, which lets an
index manipulation follow the integer, a sign and another non-negative
integer without a leading zero (0+1, 0-0); drafts 7 and 2019-09 cite
draft-handrews-relative-json-pointer-01, which has none. The draft’s grammar
puts the manipulation only before a JSON Pointer, yet its own example 0-1#
puts it before #; lexical accepts both, so 1-1# is valid too. The
function takes that choice as its second argument:
index_manipulation::allowed, the default, for 2020-12 and v1, and
index_manipulation::refused for 7 and 2019-09. The rule takes it as
relative_json_pointer_rule_t{index_manipulation::refused}. A sign that no
integer follows (0+, 0-#), or one whose integer has a leading zero
(0+01), is no manipulation, under either choice.
Addresses
is_ipv4 and is_ipv6 are Boost.URL’s own rules,
boost::urls::ipv4_address_rule and boost::urls::ipv6_address_rule, which
are also the rules a grammar of a program’s own composes. An IPv4 address is
RFC 2673’s dotted quad, each part 0 to 255 without a leading zero (RFC
3986’s dec-octet), so 192.168.0.01 is invalid. An IPv6 address is one of
RFC 4291 2.2’s three text forms, without a zone id or a prefix length.
Host names
is_hostname checks RFC 1123 2.1’s host names: labels of 1 to 63 letters,
digits and hyphens, no hyphen first or last, joined by single dots, the name
at most 253 octets, no empty label and so no trailing dot. A label that
starts with xn--, in any case, is an A-label, an internationalized label
in its ASCII form: lexical lowercases it, as UTS 46 maps an ASCII label, and
asks webcpp::idna whether IDNA2008 accepts it, decoded, canonical and with
the Bidi rule of the label alone, the verdict is_idn_hostname gives that
label. Another label with -- in its third and fourth places, an R-LDH
label such as ab--cd, is a valid host name, as RFC 1123 says, and not an
internationalized one (RFC 5890 2.3.1).
lexical judges each A-label alone, a decision of its own, so RFC 5893’s
Bidi rule across the labels of a name, section 2, is checked only by
is_idn_hostname: 0a.xn--4db is a host name, while its U-label form,
0a. and a Hebrew letter, is no internationalized host name. The two
formats differ here by that decision, as they do on R-LDH labels.
Internationalized host names
is_idn_hostname checks a host name that may hold any script, by UTS 46’s
processing and IDNA2008’s validity, through idna’s to_ascii with
its default options (idna’s
strict profile). The name is mapped as UTS 46 says, so fullwidth digits, an
ignored U+200B, a name not in NFC and the ideographic full stop U+3002 are
valid where IDNA2008 accepts the result; then every label must be valid in
IDNA2008, CONTEXTO and the Bidi rule across the labels included, and the
name fit DNS’s lengths in its ASCII form: labels of at most 63 octets, the
name at most 253, and no trailing dot. An R-LDH label such as ab--cd is
a host name and not an internationalized one, and the Bidi rule spans an
internationalized name’s labels where is_hostname judges each A-label
alone. The two formats side by side:
| String | is_hostname |
is_idn_hostname |
|---|---|---|
|
valid |
invalid |
|
valid |
invalid |
|
invalid |
invalid |
|
valid |
valid |
|
invalid |
valid |
A refused name’s reason is idna’s: the rule answers the idna::error that
to_ascii returned, contexto for a middle dot outside l·l, bidi for
0a. and a Hebrew letter.
E-mail addresses
is_email checks RFC 5321 4.1.2’s Mailbox, the address of an SMTP
envelope: a local part of atoms joined by dots or a quoted string, at most
64 octets, then @ and a host name, or an address literal, [192.0.2.1] or
[IPv6:2001:db8::1], the tag in any case. RFC 5321’s other literals need a
tag registered with IANA, and IPv6 is the only one, so
[RFC-5322-domain-literal] is invalid. RFC 5322’s comments and display
names are not part of a Mailbox. The whole Mailbox is at most 254 octets:
RFC 5321 4.5.3.1.3 limits a path to 256 octets, its angle brackets
included.
A literal’s addresses are judged by Boost.URL’s rules, RFC 3986’s IPv4
address and RFC 4291’s IPv6 address, rather than by RFC 5321 4.1.3’s own
Snum and IPv6-comp: an IPv4 part with a leading zero, [001.2.3.4],
which Snum allows, is invalid, and an IPv6 address whose :: stands for
a single group, [IPv6:1:2:3:4:5:6::8], which IPv6-comp refuses, is
valid.
Its address literal is a composition of Boost.URL’s combinators,
tuple_rule, variant_rule, delim_rule and squelch, over Boost.URL’s
ipv4_address_rule and ipv6_address_rule. The domain is not a
variant_rule alternative: the rule looks for [ and then asks the
literal’s rule or hostname_rule, so that the reason a host name was
refused, idna’s for an A-label, reaches the caller; Boost.URL’s
variant_rule answers mismatch when every alternative fails. A grammar of a
program’s own composes lexical’s rules the same way (Composing rules).
is_idn_email checks RFC 6531’s internationalized Mailbox: the local part
may hold any well-formed non-ASCII UTF-8, C1 controls and noncharacters
included, and is not normalized; the domain is an internationalized host
name or an address literal. A quoted pair stays ASCII. Its lengths are those
of the Mailbox as written, in UTF-8: the local part at most 64 octets and the
whole at most 254, the form an SMTPUTF8 envelope carries (RFC 6531 extends
RFC 5321’s Mailbox without changing its limits, which RFC 5321 counts in
octets), whatever the domain’s ASCII form measures; the domain also fits
DNS’s lengths in its ASCII form, as is_idn_hostname asks.
URIs and IRIs
is_uri is Boost.URL’s parse_uri, RFC 3986’s URI, a scheme required and
a fragment allowed, and is_uri_reference is Boost.URL’s
parse_uri_reference, a URI or a relative reference, each with a guard of
lexical’s, and so are their rules, uri_rule and uri_reference_rule.
RFC 3986 4.2 gives a relative
reference that has an authority a path-abempty, empty or led by /.
Boost.URL 1.92 accepts //example.com:abc/p, read as host example.com, an
empty port and the path abc/p, and //a@b@example.com/, read as user a,
host b and the path @example.com/. With a scheme it refuses both, and
stops the URI at the authority, so that inside a larger grammar Boost.URL’s
rule matches http://a@b of http://a@b@example.com/. lexical refuses a
relative reference whose path after an authority is neither empty nor led by
/, and uri_reference_rule refuses both forms alike with error::invalid.
The guard stays until a Boost release refuses those references itself.
RFC 3986 holds [ and ] only around an IP literal (3.2.2): a path, a query
and a fragment hold them percent-encoded, as %5B and %5D. Boost.URL 1.92
refuses them in a path and a fragment, and accepts them in a query:
http://a/?[x] is a URI for Boost.URL. lexical refuses a bracket in a query,
in is_uri, is_uri_reference, is_iri, is_iri_reference and their rules
alike, which give error::invalid for it inside a larger grammar; an IP
literal, http://[::1]/, and %5B in a query stay valid. This guard stays
until a Boost release refuses those brackets itself.
RFC 3986 3.5 gives a fragment pchar, / and ? alone: the first #
starts the fragment, and a second is held only percent-encoded, as %23.
Boost.URL 1.92 adds # to its fragment characters on purpose, so
http://a/#x#y is a URI for Boost.URL, whose fragment is x#y. lexical
refuses a # in a fragment, in the same four functions and their rules,
which give error::invalid for it inside a larger grammar; #x%23y stays
valid. This guard stays until a Boost release refuses it itself.
is_iri and is_iri_reference check RFC 3987’s IRI and IRI reference,
which allow non-ASCII code points, by mapping the IRI to a URI as RFC 3987
3.1 says and handing it to Boost.URL. Each non-ASCII code point must be
well-formed UTF-8 and in ucschar, or in iprivate within the query; the
bidirectional formatting characters U+200E, U+200F and U+202A to U+202E are
refused anywhere, as RFC 3987 4.1 requires, and so is any non-ASCII code
point inside an IP literal: RFC 3987 takes its IP literal from RFC 3986,
ASCII alone. Each octet of a non-ASCII code point
then becomes %XX, which RFC 3986 allows everywhere else that RFC 3987
allows ucschar, so a non-ASCII code point in a scheme or a port is refused
by Boost.URL. No IDNA is involved: an IRI’s host is a registered name of any
ucschar.
The mapped URI needs contiguous storage. An ASCII IRI is parsed as it is,
never copied; a non-ASCII one is mapped into a buffer of 1,024 octets on the
stack, which holds any IRI of up to 341 octets; a longer one takes one buffer
of its mapped length from the memory resource given to
is_iri(s, resource), or from std::pmr::get_default_resource(). A resource
of a program’s own, here a buffer that refuses to grow:
std::array<std::byte, 4096> storage{};
std::pmr::monotonic_buffer_resource resource(storage.data(), storage.size(),
std::pmr::null_memory_resource());
std::string long_iri = "http://example.com/";
for (int i = 0; i < 300; ++i) {
long_iri += "\303\251"; // 300 e with an acute accent: 1,819 octets mapped, past 1,024
}
std::cout << std::boolalpha;
std::cout << "short: "
<< lexical::is_iri("http://\306\222\303\270\303\270.example/\317\200", resource)
<< '\n';
std::cout << "long: " << lexical::is_iri(long_iri, resource) << '\n';
std::cout << "bidi: " << lexical::is_iri("http://a/\342\200\216", resource) << '\n';
It prints:
short: true long: true bidi: false
RFC 3986 3.2.2’s IP literal holds an IPv6 address or an IPvFuture, and no
zone identifier. RFC 6874 added one, http://[fe80::1%25eth0]/, which
Boost.URL 1.92 takes; RFC 9844 obsoleted RFC 6874 in 2025 and reverted its
change to RFC 3986. lexical refuses a zone identifier, in the same four
functions and their rules, which give error::invalid for it inside a larger
grammar; %25 outside an IP literal stays valid. This guard stays until a
Boost release refuses zone identifiers itself. Each guard, and the one verdict
of Boost.URL that lexical keeps though RFC 3986 differs, is listed in
Known deviations.
Boost.URL is a compiled library: a program that uses these formats links
/webcpp//boost_url, which /webcpp/lexical//lexical brings. Measured on
2026-10-09 with Boost 1.92 and wasi-sdk 34, built with b2’s release flags
(-O3, wasm exceptions) and stripped at link time, a wasm32-wasip2 program
that calls is_uri is 85,625 bytes larger than an empty one.
Known deviations
lexical is faithful to RFC 3986, the reference JSON Schema names for these
formats, where Boost.URL 1.92 is more liberal. lexical refuses four things
Boost.URL accepts: a relative reference whose path after an authority is
neither empty nor led by /; [ or ] in a query; # in a fragment; and
a zone identifier in an IP literal. Its rules also refuse a reference that
Boost.URL’s would stop at an authority before a path segment, as at the
second @ of http://a@b@example.com/. The tests pin each of these
verdicts.
lexical keeps one verdict of Boost.URL that RFC 3986 does not give, since it
never loosens Boost.URL: an IPvFuture led by an uppercase V,
http://[V1.x]/, is refused, though RFC 5234 makes ABNF’s quoted strings
case-insensitive and RFC 3986’s "v" matches it; http://[v1.x]/ is
valid.
These are all the differences found on 2026-10-09, when the verdicts of Boost.URL 1.92 and of lexical were compared with a transcription of RFC 3986’s ABNF, on inputs that put every ASCII character but NUL and line feed into each part of a reference, and on references generated at random.
URI templates
is_uri_template checks RFC 6570’s URI Template of any level, without
expanding it: literals, and expressions in braces with an optional operator
and comma-separated variables, each with a prefix length of 1 to 9999 or an
explode *. Erratum 6937, verified in 2022, makes the apostrophe a literal,
as JSON Schema’s suite expects. The operators RFC 6570 reserves for future
use, the equals sign, the comma, the exclamation mark, the at sign and the
vertical bar, are accepted, as its ABNF accepts them. A literal may be a
ucschar or iprivate code point, so a template of an IRI is valid too.
Regular expressions
is_regex answers whether a string is a regular expression, JSON Schema’s
regex: ECMA-262’s Pattern in u mode, with ECMAScript 2025’s modifiers,
(?i:...), and its duplicate group names, (?<y>...)|(?<y>...). It is
declared in <webcpp/lexical/regex.hpp>, the one header of lexical that
brings the Unicode tables of ECMA-262’s classes: <webcpp/lexical.hpp> leaves
it out, and a program that never validates a pattern does not compile them.
for (const std::string_view pattern : {
R"(^\p{Letter}+$)",
R"((?<year>\d{4})-(?<month>\d{2}))",
R"((?<=\$\d*)[0-9])",
"^(abc]",
R"(\Aabc\z)",
"(?i)abc",
"(?i:abc)",
}) {
std::cout << pattern << " -> " << (webcpp::lexical::is_regex(pattern) ? "valid" : "invalid")
<< '\n';
}
It prints:
^\p{Letter}+$ -> valid
(?<year>\d{4})-(?<month>\d{2}) -> valid
(?<=\$\d*)[0-9] -> valid
^(abc] -> invalid
\Aabc\z -> invalid
(?i)abc -> invalid
(?i:abc) -> valid
How a pattern is judged
A pattern is valid when ECMA-262 accepts it as a Pattern in u mode, early
errors included: when new RegExp(pattern, "u") does not throw a
SyntaxError. lexical’s validator reads the pattern as that grammar reads it,
and refuses what the grammar refuses there: Annex B’s escapes and classes,
\a, \- outside a class, \8, an octal escape; Perl’s \A, \Z and \z;
a group of another dialect, (?P<n>...), (?#...), a leading (?i); a
property ECMA-262 does not name, as \p{letter} or \p{Script=Foo}; a
backreference to a group the pattern does not hold; two groups of one name
that a match could both hold. A pattern that is not well-formed UTF-8 is
refused, and a NUL is a literal like any other code point.
Valid means that the syntax and the early errors accept the pattern, and
nothing more. is_regex compiles no pattern and runs none: it says nothing of
how long a matcher takes on a valid pattern, nor of the limits an engine sets
on the program it builds from one. The property names \p{...} accepts are
Unicode 17.0.0’s, read from the generated tables
(The Unicode tables): no ICU and no std::locale.
ECMA-262 allows a lookbehind of any width, (?<=\$\d*), and so does
is_regex: it never measures a lookbehind, since it compiles nothing.
is_regex has no rule: a pattern has no grammar of its own inside a longer
input, so is_regex judges a whole string.
Bounds
Two bounds keep a hostile pattern, which JSON Schema meets in an instance,
from taking the stack or the time of a program. Past one of them, is_regex
answers false without judging the pattern, though ECMA-262 may allow it:
| Constant | Value | Bounds |
|---|---|---|
|
65,536 |
a pattern’s bytes, refused before they are read: the validator reads parts of a pattern again, so a bound on its length bounds its time |
|
32 |
groups, lookarounds and modifiers one inside the other: the validator descends into a group by calling itself, so the nesting bounds its stack |
What it allocates
is_regex allocates nothing, on any target. It takes no memory resource: its
reader works on the pattern’s own bytes and keeps its state on the stack, to
the depth max_regex_nesting allows. So <webcpp/lexical/regex.hpp> keeps
lexical’s rule that a validator allocates nothing, as the allocation table says
(Allocation).
Compared with V8
A test of lexical, regex_v8, compares is_regex with V8 on
24,297 patterns, of which 16,475 are valid by V8’s
verdict. The patterns are drawn at random, from seeds 2 to 9 of Python’s
random.Random, from a grammar of atoms, groups of every kind,
backreferences, assertions, quantifiers and defects; every name \p{...}
accepts, under each of its forms, and the same names misspelt; every pattern
the JSON-Schema-Test-Suite’s schemas hold, in pattern and patternProperties,
and every string of its tests of the format regex; and the cases the grammar
does not draw: ECMAScript 2025’s modifiers and duplicate group names,
lookbehinds of every width, escapes of every kind, and classes and quantifiers
at their edges. V8’s verdict is new RegExp(pattern, "u") throwing a
SyntaxError or not, written by the oracle of test/oracle, which runs the
pinned Node, 26.7.0, whose V8 is 14.6 and whose Unicode is 17.0. On each of
these patterns the verdict of is_regex is V8’s, on every target
(Testing).
To check the committed verdicts against the pinned Node, and is_regex
against them:
b2 -a libs/lexical/test/oracle//oracle
b2 -a libs/lexical/test//regex_v8
After a change to the patterns, update-expected writes the verdicts again:
b2 libs/lexical/test/oracle//update-expected
The Unicode tables
tools/generate_tables.py, in lexical’s repository, writes
<webcpp/lexical/detail/regex_tables.hpp> from Unicode’s data files of
version 17.0.0, pinned in tools/unicode.json, each by its URL
under https://www.unicode.org/Public/17.0.0/ and its SHA-256: a
file its cache lacks is downloaded, every file is hashed, and a digest that
differs stops it before it writes anything. Before it writes, it checks what
the validator and the traits assume of the data: General_Category has 30
values that are no group; every value a file holds is one
PropertyValueAliases.txt names; each of ECMA-262’s binary properties holds
a code point; every name is ASCII and names one value; the classes fit the
traits’ mask; and no simple case folding orbit holds more than four code
points. A script that no code point has, Katakana_Or_Hiragana, gets no name,
as ECMA-262’s table of the values of Script leaves it out.
tools/generate_patterns.py writes the patterns regex_v8 reads, the same
way.
The own lane generated runs both generators again, into the build
directory, and compares each output with the committed file, byte for byte;
update-generated writes them in place, the one writer of the generated
files. The ordinary lanes never run them, since a generator may need the
network. The data are Unicode’s, under the Unicode License v3, whose notice
is in the appendix "Unicode data".
b2 -a libs/lexical/test//generated
b2 libs/lexical/test//update-generated
Composing rules
Every format but regex is also a Boost.URL rule, in
webcpp::lexical::grammar: an object whose type <name>_rule_t is public,
so a rule that takes a parameter, time_rule_t{leap_seconds::refused} or
iri_rule_t{&resource}, is spelled without a factory. A rule yields the
text it matched, as a grammar::text; uri_rule and uri_reference_rule
yield Boost.URL’s url_view. ipv4 and ipv6 are Boost.URL’s own rules,
boost::urls::ipv4_address_rule and ipv6_address_rule.
A rule composes with Boost.URL’s combinators, tuple_rule, variant_rule,
optional_rule, range_rule, into a grammar of a program’s own: an
internationalized host and an optional port, bücher.example:8080, are a
tuple_rule of idn_hostname_rule and an optional_rule of another
tuple_rule, a colon, squelch(delim_rule(':')), then
unsigned_rule<std::uint16_t>, which yields the host’s text and the port’s
number; a rule that refuses says whose rule it was, through its error’s
category:
constexpr auto idn_host_port = urlg::tuple_rule(
fg::idn_hostname_rule,
urlg::optional_rule(urlg::tuple_rule(urlg::squelch(urlg::delim_rule(':')),
urlg::unsigned_rule<std::uint16_t>{})));
for (const std::string_view text : {
"b\303\274cher.example:8080",
"example.com",
"a\302\267b.example:80",
"example.com:99999",
}) {
const auto parsed = urlg::parse(text, idn_host_port);
if (parsed.has_error()) {
const boost::system::error_code error = parsed.error();
std::cout << text << " -> refused by " << error.category().name() << '\n';
continue;
}
const auto& [host, port] = *parsed;
std::cout << text << " -> host " << host;
if (port) {
std::cout << ", port " << *port;
}
std::cout << '\n';
}
It prints:
bücher.example:8080 -> host bücher.example, port 8080 example.com -> host example.com a·b.example:80 -> refused by webcpp.idna example.com:99999 -> refused by boost.url.grammar
Where a rule stops inside a longer input is part of its contract:
| Rule | Stops |
|---|---|
the ASCII rules |
where their grammar does |
|
at the first character outside letters, digits, |
|
at the first ASCII character outside letters, digits, |
|
as |
|
where the domain or the address literal does |
|
at the first byte no IRI holds: an ASCII control, the space, the double quote, the less-than and greater-than signs, the backslash, the circumflex, the grave accent, a brace or the vertical bar |
|
at the first byte that is neither a literal nor the start of an expression; an expression or a percent sign that starts and breaks makes it fail |
|
at the end of the input: a token holds every other character |
Each validates the text it took and fails as a whole rather than match a
shorter prefix, and a rule that fails leaves its input where it was.
idna_label_rule is a terminal of lexical’s own that asks webcpp::idna for
its verdict, so a grammar joins labels with separators of its own. It judges
each label alone: a grammar that joins labels into a name checks what spans
the name itself, RFC 5893’s Bidi rule across its labels (section 2) and its
253 octets in the ASCII form, or hands the whole name to
idn_hostname_rule, which checks both. Joined by a grammar’s own dots,
0a. and a label of a Hebrew letter are two valid labels and no valid name.
An internationalized rule’s error is idna’s, the idna::error that refused
the name (Errors), but only where nothing discards it: Boost.URL’s
variant_rule answers mismatch when every alternative fails, whatever
each one said. lexical’s e-mail rules look for [ themselves rather than
make the domain an alternative, so that idna’s reason reaches the caller; a
grammar that needs that reason does the same.
Two facts of Boost.URL shape a composition. A range_rule over a rule
larger than 128 bytes keeps it in a pool of Boost.URL’s own, which
allocates: pass such a rule through boost::urls::grammar::ref, as lexical
does. And parse of a whole string fails with error::leftover when the
rule stops early, which is how a validator refuses trailing input.
Errors
A validator answers bool: whether the string is in the format. A rule
answers a grammar::result, the text it matched or why it refused, and
lexical has no error category of its own:
-
boost::urls::grammar::error::mismatch: no text of the format starts where the rule was asked to match, so avariant_ruletries its next alternative; -
boost::urls::grammar::error::invalid: the format’s text started there and broke one of its constraints, a month 13 or a leap second at the wrong minute; -
boost::urls::grammar::error::leftover, fromparseon a whole string: the format’s text ended before the string did; -
an error of
webcpp::idna, from the rules of internationalized names: the reason UTS 46 or IDNA2008 refused the name.
lexical raises no exception of its own, and builds without exceptions.
WEBCPP_LEXICAL_NO_EXCEPTIONS, defined without exceptions or by the
developer, changes nothing in it: it exists so that a program can set it for
every webcpp library alike. Only an allocation can throw, std::bad_alloc
from the default resource or the global operator new: an IRI function’s
resource (Allocation). is_regex allocates nothing and is
noexcept: a pattern it refuses is answered false, never an exception
(How a pattern is judged).
Allocation
A validator and a rule allocate nothing, but the IRI functions, which allocate only through a memory resource, where the table below says:
| Function or rule | Allocates |
|---|---|
every validator and rule but those below |
never: Boost.URL’s views and lexical’s rules hold no storage, idna works in fixed storage, a |
|
never for an ASCII IRI or one whose mapped URI fits 1,024 octets; beyond, one buffer of the mapped length, from the resource given, else |
A test counts every call of the global operator new its program makes,
over every validator and rule, on long and hostile inputs, a megabyte of
each format among them, and finds none but those the table names, on every
target.
The stack holds the rest: an IRI’s buffer of 1,024 octets, idna’s working
storage of a label, and the descent of is_regex into a pattern’s groups,
which max_regex_nesting bounds (Bounds).
The JSON Schema suite
The official JSON-Schema-Test-Suite holds, for each draft, the format tests
of optional/format/, and for v1 those of format/, which v1 requires. A
program of lexical’s tests runs each string test against the validator of its
format, on every target lexical builds for: is_time(s,
leap_seconds::refused) for v1’s time, is_relative_json_pointer(s,
index_manipulation::refused) for the relative JSON Pointers of drafts 7 and
2019-09, and the same call in every other draft. A test whose instance is
not a string checks json_schema’s rule that a format applies to strings
only, and the unknown format json_schema’s handling of a format it does
not know: neither is a question for a validator.
| Dialect | String tests | Passing |
|---|---|---|
draft 4 |
248 |
248 |
draft 6 |
348 |
348 |
draft 7 |
684 |
684 |
draft 2019-09 |
753 |
753 |
draft 2020-12 |
753 |
753 |
v1 |
754 |
754 |
all |
3,540 |
3,540 |
A test expected to fail is listed in its dialect’s known-failure list with its reason; the only reason allowed is a difference of Unicode versions, since idna’s tables are those of Unicode 17.0.0. Every list is empty. The program fails on a failure no list names, and on a listed test that passes.
The suite’s tests that need a regular expression to match, its pattern
and patternProperties keywords, are json_schema’s: lexical does not search.
Every pattern they hold is valid for is_regex, as for V8
(Compared with V8).
Guarantees
-
For every format but
regex,is_x(s)andparse(s, x_rule)give the same answer for every string. -
No function or rule allocates but those the allocation table names: the IRI functions, only through a memory resource.
-
Every function refuses a string that is not well-formed UTF-8.
-
is_regexanswers every byte string, a value, and never throws: a pattern past one of its bounds is answeredfalsebefore it can take more stack or time than the bounds allow. -
The Unicode tables and the patterns compared with V8 are what their generators write from the pinned files, byte for byte.
Testing
lexical is tested natively, on wasm32-wasip2 and wasm32-wasip3 under wasmtime, and on emscripten under node, from the superproject’s root:
b2 libs/lexical/test libs/lexical/example
b2 toolset=clang-wasip2 testing.launcher=wasmtime libs/lexical/test libs/lexical/example
b2 toolset=clang-wasip3 testing.launcher=wasmtime libs/lexical/test libs/lexical/example
b2 toolset=emscripten libs/lexical/test libs/lexical/example
Its 41 tests are written with Boost’s lightweight_test: each public
header compiled alone, the configuration macro compiled three times, the
terminals every format shares, the cases of each format, the rules composed
with Boost.URL’s combinators, what each validator allocates, the run of the
JSON Schema suite’s 3,540 string tests (The JSON Schema suite), and the
comparison of is_regex with V8 on 24,297 patterns
(Compared with V8). Its 4 examples run on every target too,
each compared with the output the page shows.
The suite’s files, and lexical’s known-failure lists and patterns, reach a
WASI program through webcpp.data, the directory wasmtime is given with
--dir, and an emscripten program through node’s file system.
Two own lanes run apart from the targets’, each natively. oracle asks V8,
the pinned Node’s, for its verdict on every pattern regex_v8 reads, and
compares them with the committed ones, which only update-expected writes;
generated runs the generators of the Unicode tables and of the patterns
again, and compares their outputs with the committed files
(The Unicode tables):
b2 -a libs/lexical/test/oracle//oracle
b2 -a libs/lexical/test//generated
b2 libs/lexical/test/oracle//update-expected
The test matrix of every lane is published at https://webcpporg.github.io/report/.
Reference
Every name lexical declares, in the namespaces webcpp::lexical and
webcpp::lexical::grammar, from the Doc Comments of its headers: each
function, rule, type and constant with its declaration, what it does and
how it fails. The other sections teach the library; this one is where a name
is looked up.
Macros
| Name | Description |
|---|---|
Defined when lexical is built without exceptions: when webcpp has none (the compiler has none, or the developer defined |
webcpp::lexical
Namespaces
| Name |
|---|
Enums
| Name | Description |
|---|---|
Whether a relative JSON Pointer may move its array index with a sign and an integer. |
|
Whether a time may hold second 60, a leap second. |
Functions
| Name | Description |
|---|---|
Whether |
|
Whether |
|
Whether |
|
Whether |
|
Whether |
|
Whether |
|
Whether |
|
Whether |
|
Whether |
|
|
|
|
|
Whether |
|
Whether |
|
Whether |
|
Whether |
|
Whether |
|
Whether |
|
Whether |
|
Whether |
Variables
| Name | Description |
|---|---|
The longest pattern |
|
The deepest a pattern’s groups may nest for |
webcpp::lexical::grammar
Types
| Name | Description |
|---|---|
The rule of RFC 3339 5.6’s |
|
The rule of RFC 3339 5.6’s |
|
The rule of RFC 3339 appendix A’s |
|
The rule of RFC 5321 4.1.2’s Mailbox: a local part, the at sign, and a domain or an address literal. |
|
The rule of a host name: RFC 1123 2.1’s labels, with each A-label judged as |
|
The rule of RFC 6531 3.3’s internationalized Mailbox: |
|
The rule of an internationalized host name: UTS 46’s processing and IDNA2008’s validity, through |
|
The rule of one label of an internationalized host name, a terminal of lexical’s own that asks |
|
The rule of RFC 3987 2.2’s IRI-reference: an IRI or a relative reference, checked and mapped as |
|
The rule of RFC 3987 2.2’s IRI: an IRI checked code point by code point, mapped to a URI, and parsed by |
|
The rule of RFC 6901 section 3’s json-pointer: zero or more reference tokens, each led by |
|
The rule of the relative-json-pointer of draft-bhutton-relative-json-pointer-00 section 3 and draft-handrews-relative-json-pointer-01 section 3: a non-negative integer, an optional index manipulation, then |
|
The rule of RFC 3339 5.6’s |
|
The rule of RFC 3986 4.1’s URI-reference: Boost.URL’s |
|
The rule of RFC 3986 3’s URI: Boost.URL’s |
|
The rule of RFC 6570 section 2’s URI-Template, with erratum 6937: literals and expressions. |
|
The rule of RFC 9562 section 4’s UUID: 32 hexadecimal digits in groups of 8, 4, 4, 4 and 12, joined by hyphens. |
Type Aliases
Variables
| Name | Description |
|---|---|
The rule of RFC 3339’s |
|
The rule of RFC 3339’s |
|
The rule of RFC 3339 appendix A’s |
|
The rule of RFC 5321’s Mailbox. |
|
The rule of a host name. |
|
The rule of RFC 6531’s Mailbox. |
|
The rule of an internationalized host name. |
|
The rule of one internationalized label. |
|
The rule of RFC 3987’s IRI-reference, with the default resource. |
|
The rule of RFC 3987’s IRI, with the default resource; |
|
The rule of RFC 6901’s json-pointer. |
|
The rule of the relative JSON pointer, index manipulation allowed; |
|
The rule of RFC 3339’s |
|
The rule of RFC 3986’s URI-reference, guarded. |
|
The rule of RFC 3986’s URI, guarded. |
|
The rule of RFC 6570’s URI-Template. |
|
The rule of RFC 9562’s UUID. |
webcpp::lexical::grammar::result
What a rule returns: the value it matched, or the error that refused its input.
Synopsis
Declared in <webcpp/lexical/grammar.hpp>
template<class T>
using result = boost::system::result<T>;
Template Parameters
| Name | Description |
|---|---|
T |
The rule’s value type. |
See Also
"Errors", in the guide.
webcpp::lexical::grammar::text
The text a rule of lexical matched, a view of its input.
Description
It is Boost.URL’s text type, which converts to std::string_view.
See Also
"Composing rules", in the guide.
webcpp::lexical::grammar::date_rule_t
The rule of RFC 3339 5.6’s full-date: a year, a month and a day that exists.
Description
4DIGIT "-" 2DIGIT "-" 2DIGIT, ASCII digits only; the month 01 to 12, the day 01 to the month’s length, February 29 only in a Gregorian leap year. It stops after the day.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches a |
See Also
"Dates and times", in the guide.
webcpp::lexical::grammar::date_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::date_rule_t::parse
Matches a full-date at it.
Synopsis
Declared in <webcpp/lexical/date_time.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched; error::mismatch when no digit starts it; error::invalid when it started and broke a constraint (Boost.URL’s grammar errors).
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::date_time_rule_t
The rule of RFC 3339 5.6’s date-time: a full-date, T in either case, a full-time.
Description
Leap seconds are allowed, as every draft of JSON Schema, v1 included, says of date-time. It stops after the offset.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches a |
See Also
"Dates and times", in the guide.
webcpp::lexical::grammar::date_time_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::date_time_rule_t::parse
Matches a date-time at it.
Synopsis
Declared in <webcpp/lexical/date_time.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched; error::mismatch when no digit starts it; error::invalid when it started and broke a constraint.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::duration_rule_t
The rule of RFC 3339 appendix A’s duration, exactly: P, then a date part, a time part, or weeks alone.
Description
Years, months and days in that order and each optional after the first given, then T and hours, minutes and seconds likewise; or a number of weeks alone. No fraction, no sign, any number of digits. The designators are letters of the ABNF, so either case matches (RFC 5234 2.3). It stops where the ABNF does: after P1Y, the 2D of P1Y2D is not its.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches a |
See Also
"Dates and times", in the guide.
webcpp::lexical::grammar::duration_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::duration_rule_t::parse
Matches a duration at it.
Synopsis
Declared in <webcpp/lexical/date_time.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched; error::mismatch when no P starts it; error::invalid when it started and broke the grammar.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::email_rule_t
The rule of RFC 5321 4.1.2’s Mailbox: a local part, the at sign, and a domain or an address literal.
Description
The local part is a Dot-string of atoms (RFC 5322’s atext) or a Quoted-string, at most 64 octets. The domain is hostname_rule, A-labels included, whose error, idna’s for an A-label, the rule returns as it is; an address literal is [] and an IPv4 address ], or [IPv6:] and an IPv6 address ], the tag in any case: RFC 5321’s General-address-literal needs a tag registered with IANA, and IPv6 is the only one. The whole Mailbox is at most 254 octets, RFC 5321 4.5.3.1.3’s path of 256 less its angle brackets. It stops where the domain or the literal does.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches a Mailbox at |
See Also
"Addresses", in the guide.
webcpp::lexical::grammar::email_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::email_rule_t::parse
Matches a Mailbox at it.
Synopsis
Declared in <webcpp/lexical/email.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched; error::mismatch when no local part starts at it; error::invalid when the rest breaks the grammar or the Mailbox is longer than 254 octets; idna’s error when idna refuses an A-label of the domain.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::hostname_rule_t
The rule of a host name: RFC 1123 2.1’s labels, with each A-label judged as idn-hostname judges it.
Description
ASCII only. Labels of 1 to 63 letters, digits and hyphens, no hyphen first or last, joined by single dots, no dot first or last; the name at most 253 octets. A label that starts with xn-- in any case is an A-label: lowercased and checked by webcpp::idna::check_label (RFC 5891 5.4: decoded, IDNA2008, the Bidi rule of the label alone, canonical). Another label with two hyphens in its third and fourth places is valid, as RFC 1123 says. It takes the run of letters, digits, hyphens and dots at its start and validates it whole, never a shorter prefix.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches a host name at |
See Also
"Addresses", in the guide.
webcpp::lexical::grammar::hostname_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::hostname_rule_t::parse
Matches a host name at it.
Synopsis
Declared in <webcpp/lexical/hostname.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched; error::mismatch when no letter, digit, hyphen or dot is at it; error::invalid when the run is no host name; idna’s error when idna refuses an A-label.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::idn_email_rule_t
The rule of RFC 6531 3.3’s internationalized Mailbox: email_rule with UTF-8 in the local part and an internationalized domain.
Description
atext and qtextSMTP also hold any well-formed non-ASCII UTF-8 sequence (RFC 6532 3.1, C1 controls and noncharacters included), quoted-pairSMTP stays ASCII, the local part is at most 64 octets and is not normalized; the domain is idn_hostname_rule, whose error, idna’s, the rule returns as it is, or an address literal. The whole Mailbox is at most 254 octets as written, in UTF-8, the form an SMTPUTF8 envelope carries, whatever its domain’s ASCII form measures.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches an internationalized Mailbox at |
See Also
"Addresses", in the guide.
webcpp::lexical::grammar::idn_email_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::idn_email_rule_t::parse
Matches an internationalized Mailbox at it.
Synopsis
Declared in <webcpp/lexical/email.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched; error::mismatch when no local part starts at it; error::invalid when the rest breaks the grammar or the Mailbox is longer than 254 octets; idna’s error when idna refuses the domain.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::idn_hostname_rule_t
The rule of an internationalized host name: UTS 46’s processing and IDNA2008’s validity, through webcpp::idna::to_ascii.
Description
idna’s default options: UTS 46’s mapping, nontransitional, every check, the DNS lengths, and IDNA2008’s stricter validity (CONTEXTO, NV8 and XV8 refused). So fullwidth digits, an ignored U+200B, a name not in NFC and the dots U+3002, U+FF0E and U+FF61 are valid where IDNA2008 allows the result. It takes the run up to the first ASCII byte outside letters, digits, - and . (every non-ASCII byte belongs to it, since UTS 46 may map it) and validates it whole.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches an internationalized host name at |
See Also
"Addresses", in the guide.
webcpp::lexical::grammar::idn_hostname_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::idn_hostname_rule_t::parse
Matches an internationalized host name at it.
Synopsis
Declared in <webcpp/lexical/hostname.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched; error::mismatch when no name’s byte is at it; else idna’s error when idna refuses the run.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::idna_label_rule_t
The rule of one label of an internationalized host name, a terminal of lexical’s own that asks webcpp::idna for its verdict.
Description
The run stops also at ., U+3002, U+FF0E and U+FF61, so a grammar composes labels with its own separators. The label is checked as idn_hostname_rule checks a name of one label, alone: a grammar that joins labels into a name checks what spans the name itself, RFC 5893’s Bidi rule across its labels (section 2) and its 253 octets in the ASCII form, or hands the whole name to idn_hostname_rule, which checks both.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches one internationalized label at |
See Also
"Composing rules", in the guide.
webcpp::lexical::grammar::idna_label_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::idna_label_rule_t::parse
Matches one internationalized label at it.
Synopsis
Declared in <webcpp/lexical/hostname.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched; error::mismatch when no label starts at it; else idna’s error.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::iri_reference_rule_t
The rule of RFC 3987 2.2’s IRI-reference: an IRI or a relative reference, checked and mapped as iri_rule_t does, then parsed by uri_reference_rule.
Description
The empty reference is valid, so the rule matches empty text where a byte no IRI holds is at the start, and never answers mismatch.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches an IRI-reference at |
Data Members
| Name | Description |
|---|---|
The resource of a mapped URI longer than 1,024 octets; null for the default resource. |
See Also
"URIs and IRIs", in the guide.
webcpp::lexical::grammar::iri_reference_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::iri_reference_rule_t::parse
Matches an IRI-reference at it.
Synopsis
Declared in <webcpp/lexical/uri.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const;
Exceptions
| Name | Thrown on |
|---|---|
|
When the resource cannot allocate, or what it throws instead. |
Return Value
The text matched; error::invalid when the run is no IRI reference.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::iri_reference_rule_t::resource
The resource of a mapped URI longer than 1,024 octets; null for the default resource.
webcpp::lexical::grammar::iri_rule_t
The rule of RFC 3987 2.2’s IRI: an IRI checked code point by code point, mapped to a URI, and parsed by uri_rule.
Description
A non-ASCII code point must be well-formed UTF-8 and in ucschar, or iprivate in the query; the bidirectional formatting characters are refused anywhere (RFC 3987 4.1), and so is any non-ASCII code point inside an IP literal, which RFC 3987 takes from RFC 3986, ASCII alone. Each octet of a non-ASCII code point maps to %XX, which RFC 3986 allows elsewhere where RFC 3987 allows ucschar, so a non-ASCII scheme or port is refused too. The rule takes the run up to the first byte no IRI holds (an ASCII control, the space, the double quote, the less-than and greater-than signs, the backslash, the circumflex, the grave accent, the braces or the vertical bar) and validates it whole; it never matches a shorter prefix.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches an IRI at |
Data Members
| Name | Description |
|---|---|
The resource of a mapped URI longer than 1,024 octets; null for the default resource. |
See Also
"URIs and IRIs", in the guide.
webcpp::lexical::grammar::iri_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::iri_rule_t::parse
Matches an IRI at it.
Synopsis
Declared in <webcpp/lexical/uri.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const;
Exceptions
| Name | Thrown on |
|---|---|
|
When the resource cannot allocate, or what it throws instead. |
Return Value
The text matched; error::mismatch when a byte no IRI holds is at it; error::invalid when the run is no IRI.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::iri_rule_t::resource
The resource of a mapped URI longer than 1,024 octets; null for the default resource.
webcpp::lexical::grammar::json_pointer_rule_t
The rule of RFC 6901 section 3’s json-pointer: zero or more reference tokens, each led by /.
Description
A token holds any code point but / and ~, NUL included, and ~0 or ~1; the input is decoded as UTF-8 and must be well-formed. The empty pointer is valid, so the rule matches empty text where no / starts the input, and never answers mismatch. Once a / starts it, inside a larger grammar it runs to the end of the input, since a token holds every character the grammar could continue with.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches a json-pointer at |
See Also
"Identifiers", in the guide.
webcpp::lexical::grammar::json_pointer_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::json_pointer_rule_t::parse
Matches a json-pointer at it.
Synopsis
Declared in <webcpp/lexical/json_pointer.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched, empty when no / starts the input; error::invalid when a token holds a ~ that is not ~0 or ~1, or ill-formed UTF-8.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::relative_json_pointer_rule_t
The rule of the relative-json-pointer of draft-bhutton-relative-json-pointer-00 section 3 and draft-handrews-relative-json-pointer-01 section 3: a non-negative integer, an optional index manipulation, then # or a json-pointer.
Description
The integer is 0 or starts with 1 to 9, so 01 is refused. The index manipulation, a sign and such an integer (0+1, 0-0), is draft-bhutton-00’s, which draft 2020-12 and v1 cite; it may come before the # too (1-1#), as the draft’s example 0-1# does though its ABNF omits it. Drafts 7 and 2019-09 cite draft-handrews-01, which has none, so index_manipulation::refused refuses it. It stops after the #, or where its json-pointer does; where a sign is not a valid manipulation, it stops before the sign.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches a relative-json-pointer at |
Data Members
| Name | Description |
|---|---|
Whether an index manipulation may follow the integer. |
See Also
"Identifiers", in the guide.
webcpp::lexical::grammar::relative_json_pointer_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::relative_json_pointer_rule_t::parse
Matches a relative-json-pointer at it.
Synopsis
Declared in <webcpp/lexical/json_pointer.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched; error::mismatch when no digit starts it; error::invalid when its json-pointer breaks a rule.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::relative_json_pointer_rule_t::manipulation
Whether an index manipulation may follow the integer.
Synopsis
Declared in <webcpp/lexical/json_pointer.hpp>
index_manipulation manipulation = index_manipulation::allowed;
webcpp::lexical::grammar::time_rule_t
The rule of RFC 3339 5.6’s full-time: a time of day and its offset from UTC.
Description
Hours 00 to 23, minutes 00 to 59, seconds 00 to 60 with any number of fraction digits, then Z or +hh:mm or -hh:mm (hh 00 to 23, mm 00 to 59); Z in either case. Second 60 is valid only under leap_seconds::allowed and when the time moved to UTC is 23:59. It stops after the offset.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches a |
Data Members
| Name | Description |
|---|---|
Whether second 60 may be valid. |
See Also
"Dates and times", in the guide.
webcpp::lexical::grammar::time_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::time_rule_t::parse
Matches a full-time at it.
Synopsis
Declared in <webcpp/lexical/date_time.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched; error::mismatch when no digit starts it; error::invalid when it started and broke a constraint.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::time_rule_t::leap
Whether second 60 may be valid.
webcpp::lexical::grammar::uri_reference_rule_t
The rule of RFC 3986 4.1’s URI-reference: Boost.URL’s uri_reference_rule, then a guard.
Description
Boost.URL 1.92 accepts a relative reference whose path after the authority is not path-abempty (RFC 3986 4.2), as //example.com:abc/p, whose port is not a number, and an authority that holds two at signs; with a scheme, it stops the URI at that authority. It also accepts "[" and "]" in a query, which RFC 3986 holds only around an IP literal, "#" in a fragment, which RFC 3986 3.5 refuses there, and RFC 6874’s zone identifier in an IP literal, which RFC 9844 withdrew. The guard refuses each with error::invalid. Otherwise the rule yields Boost.URL’s url_view of the reference, and stops where Boost.URL’s rule does.
Type Aliases
| Name | Description |
|---|---|
The rule yields Boost.URL’s view of the reference it matched. |
Member Functions
| Name | Description |
|---|---|
Matches a URI-reference at |
See Also
"URIs and IRIs", in the guide.
webcpp::lexical::grammar::uri_reference_rule_t::value_type
The rule yields Boost.URL’s view of the reference it matched.
webcpp::lexical::grammar::uri_reference_rule_t::parse
Matches a URI-reference at it.
Synopsis
Declared in <webcpp/lexical/uri.hpp>
[[nodiscard]]
result<boost::urls::url_view>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The view of the reference; Boost.URL’s error when its rule refuses the input; error::invalid when the guard does, a reference that ends at its authority before a character that starts a path segment included.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::uri_rule_t
The rule of RFC 3986 3’s URI: Boost.URL’s uri_rule, then a guard.
Description
Boost.URL 1.92 accepts "[" and "]" in a query, which RFC 3986 holds only around an IP literal, "#" in a fragment, which RFC 3986 3.5 refuses there, and RFC 6874’s zone identifier in an IP literal, which RFC 9844 withdrew, and stops a URI at an authority that holds two at signs; the guard refuses each with error::invalid. Otherwise the rule yields Boost.URL’s url_view of the URI, and stops where Boost.URL’s rule does.
Type Aliases
| Name | Description |
|---|---|
The rule yields Boost.URL’s view of the URI it matched. |
Member Functions
| Name | Description |
|---|---|
Matches a URI at |
See Also
"URIs and IRIs", in the guide.
webcpp::lexical::grammar::uri_rule_t::value_type
The rule yields Boost.URL’s view of the URI it matched.
webcpp::lexical::grammar::uri_rule_t::parse
Matches a URI at it.
Synopsis
Declared in <webcpp/lexical/uri.hpp>
[[nodiscard]]
result<boost::urls::url_view>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The view of the URI; Boost.URL’s error when its rule refuses the input; error::invalid when the guard does.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::uri_template_rule_t
The rule of RFC 6570 section 2’s URI-Template, with erratum 6937: literals and expressions.
Description
A literal is a printable ASCII character but the space, the double quote, the percent sign, the less-than and greater-than signs, the backslash, the circumflex, the grave accent, the braces and the vertical bar (the apostrophe is one, by the erratum), or a pct-encoded triplet, or a ucschar or iprivate code point. An expression is an opening brace, an optional operator (the reserved ones of op-reserve included, as the ABNF admits them), and varspecs separated by commas, each a varname with a colon and a max-length of 1 to 9999, or an asterisk, then a closing brace. The empty template is valid. The rule stops where the template does; an expression or a percent sign that starts and breaks makes it fail.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches a URI-Template at |
See Also
"URI templates", in the guide.
webcpp::lexical::grammar::uri_template_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::uri_template_rule_t::parse
Matches a URI-Template at it.
Synopsis
Declared in <webcpp/lexical/uri_template.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched, possibly empty; error::invalid when an expression or a pct-encoded triplet starts and breaks.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::uuid_rule_t
The rule of RFC 9562 section 4’s UUID: 32 hexadecimal digits in groups of 8, 4, 4, 4 and 12, joined by hyphens.
Description
Either case; the version and variant nibbles are not checked; no braces and no urn:uuid:. It stops after the twelfth digit of the last group.
Type Aliases
| Name | Description |
|---|---|
The rule yields the text it matched. |
Member Functions
| Name | Description |
|---|---|
Matches a UUID at |
See Also
"Identifiers", in the guide.
webcpp::lexical::grammar::uuid_rule_t::value_type
The rule yields the text it matched.
webcpp::lexical::grammar::uuid_rule_t::parse
Matches a UUID at it.
Synopsis
Declared in <webcpp/lexical/uuid.hpp>
[[nodiscard]]
result<text>
parse(
char const*& it,
char const* end) const noexcept;
Return Value
The text matched; error::mismatch when no hexadecimal digit starts it; error::invalid when it started and broke the shape.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
it |
The start of the input: past the match on success, else unchanged. |
end |
The end of the input. |
webcpp::lexical::grammar::date_time_rule
The rule of RFC 3339’s date-time.
Synopsis
Declared in <webcpp/lexical/date_time.hpp>
inline constexpr date_time_rule_t date_time_rule = {};
webcpp::lexical::grammar::duration_rule
The rule of RFC 3339 appendix A’s duration.
Synopsis
Declared in <webcpp/lexical/date_time.hpp>
inline constexpr duration_rule_t duration_rule = {};
webcpp::lexical::grammar::hostname_rule
The rule of a host name.
Synopsis
Declared in <webcpp/lexical/hostname.hpp>
inline constexpr hostname_rule_t hostname_rule = {};
webcpp::lexical::grammar::idn_email_rule
The rule of RFC 6531’s Mailbox.
Synopsis
Declared in <webcpp/lexical/email.hpp>
inline constexpr idn_email_rule_t idn_email_rule = {};
webcpp::lexical::grammar::idn_hostname_rule
The rule of an internationalized host name.
Synopsis
Declared in <webcpp/lexical/hostname.hpp>
inline constexpr idn_hostname_rule_t idn_hostname_rule = {};
webcpp::lexical::grammar::idna_label_rule
The rule of one internationalized label.
Synopsis
Declared in <webcpp/lexical/hostname.hpp>
inline constexpr idna_label_rule_t idna_label_rule = {};
webcpp::lexical::grammar::iri_reference_rule
The rule of RFC 3987’s IRI-reference, with the default resource.
Synopsis
Declared in <webcpp/lexical/uri.hpp>
inline constexpr iri_reference_rule_t iri_reference_rule = {};
webcpp::lexical::grammar::iri_rule
The rule of RFC 3987’s IRI, with the default resource; iri_rule_t{&resource} names another.
webcpp::lexical::grammar::json_pointer_rule
The rule of RFC 6901’s json-pointer.
Synopsis
Declared in <webcpp/lexical/json_pointer.hpp>
inline constexpr json_pointer_rule_t json_pointer_rule = {};
webcpp::lexical::grammar::relative_json_pointer_rule
The rule of the relative JSON pointer, index manipulation allowed; relative_json_pointer_rule_t{index_manipulation::refused} refuses it.
Synopsis
Declared in <webcpp/lexical/json_pointer.hpp>
inline constexpr relative_json_pointer_rule_t relative_json_pointer_rule = {};
webcpp::lexical::grammar::time_rule
The rule of RFC 3339’s full-time, leap seconds allowed; time_rule_t{leap_seconds::refused} refuses them.
webcpp::lexical::grammar::uri_reference_rule
The rule of RFC 3986’s URI-reference, guarded.
Synopsis
Declared in <webcpp/lexical/uri.hpp>
inline constexpr uri_reference_rule_t uri_reference_rule = {};
webcpp::lexical::grammar::uri_template_rule
The rule of RFC 6570’s URI-Template.
Synopsis
Declared in <webcpp/lexical/uri_template.hpp>
inline constexpr uri_template_rule_t uri_template_rule = {};
webcpp::lexical::index_manipulation
Whether a relative JSON Pointer may move its array index with a sign and an integer.
Members
See Also
"Identifiers", in the guide.
webcpp::lexical::index_manipulation::allowed
An index manipulation is valid, as in draft-bhutton-00, which 2020-12 and v1 cite.
webcpp::lexical::index_manipulation::refused
An index manipulation is refused, as in draft-handrews-01, which 7 and 2019-09 cite.
webcpp::lexical::leap_seconds
Whether a time may hold second 60, a leap second.
Members
See Also
"Dates and times", in the guide.
webcpp::lexical::leap_seconds::allowed
Second 60 is valid when the time moved to UTC is 23:59, as RFC 3339 5.7 allows.
webcpp::lexical::leap_seconds::refused
Second 60 is never valid, as JSON Schema v1’s time asks.
webcpp::lexical::is_date
Whether s is an RFC 3339 full-date, JSON Schema’s date.
Synopsis
Declared in <webcpp/lexical/date_time.hpp>
[[nodiscard]]
bool
is_date(std::string_view s) noexcept;
Return Value
parse(s, grammar::date_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"Dates and times", in the guide.
webcpp::lexical::is_date_time
Whether s is an RFC 3339 date-time, JSON Schema’s date-time.
Synopsis
Declared in <webcpp/lexical/date_time.hpp>
[[nodiscard]]
bool
is_date_time(std::string_view s) noexcept;
Return Value
parse(s, grammar::date_time_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"Dates and times", in the guide.
webcpp::lexical::is_duration
Whether s is an RFC 3339 appendix A duration, JSON Schema’s duration.
Synopsis
Declared in <webcpp/lexical/date_time.hpp>
[[nodiscard]]
bool
is_duration(std::string_view s) noexcept;
Return Value
parse(s, grammar::duration_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"Dates and times", in the guide.
webcpp::lexical::is_email
Whether s is an RFC 5321 Mailbox, JSON Schema’s email.
Synopsis
Declared in <webcpp/lexical/email.hpp>
[[nodiscard]]
bool
is_email(std::string_view s) noexcept;
Return Value
parse(s, grammar::email_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"Addresses", in the guide.
webcpp::lexical::is_hostname
Whether s is a host name, JSON Schema’s hostname.
Synopsis
Declared in <webcpp/lexical/hostname.hpp>
[[nodiscard]]
bool
is_hostname(std::string_view s) noexcept;
Return Value
parse(s, grammar::hostname_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"Addresses", in the guide.
webcpp::lexical::is_idn_email
Whether s is an RFC 6531 internationalized Mailbox, JSON Schema’s idn-email.
Synopsis
Declared in <webcpp/lexical/email.hpp>
[[nodiscard]]
bool
is_idn_email(std::string_view s) noexcept;
Return Value
parse(s, grammar::idn_email_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"Addresses", in the guide.
webcpp::lexical::is_idn_hostname
Whether s is an internationalized host name, JSON Schema’s idn-hostname.
Synopsis
Declared in <webcpp/lexical/hostname.hpp>
[[nodiscard]]
bool
is_idn_hostname(std::string_view s) noexcept;
Return Value
parse(s, grammar::idn_hostname_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"Addresses", in the guide.
webcpp::lexical::is_ipv4
Whether s is an IPv4 address in dotted-quad form, JSON Schema’s ipv4.
Synopsis
Declared in <webcpp/lexical/ip.hpp>
[[nodiscard]]
bool
is_ipv4(std::string_view s) noexcept;
Description
RFC 2673 3.2’s dotted quad, each part RFC 3986’s dec-octet, 0 to 255 without a leading zero.
Return Value
parse(s, boost::urls::ipv4_address_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"Addresses", in the guide.
webcpp::lexical::is_ipv6
Whether s is an IPv6 address, JSON Schema’s ipv6.
Synopsis
Declared in <webcpp/lexical/ip.hpp>
[[nodiscard]]
bool
is_ipv6(std::string_view s) noexcept;
Description
RFC 4291 2.2’s three text forms; no zone id, no prefix length.
Return Value
parse(s, boost::urls::ipv6_address_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"Addresses", in the guide.
webcpp::lexical::is_iri
is_iri overloads
Synopses
Declared in <webcpp/lexical/uri.hpp>
Whether s is an RFC 3987 IRI, JSON Schema’s iri.
[[nodiscard]]
bool
is_iri(std::string_view s);
Whether s is an RFC 3987 IRI, a mapped URI beyond 1,024 octets taken from resource.
[[nodiscard]]
bool
is_iri(
std::string_view s,
std::pmr::memory_resource& resource);
Exceptions
| Name | Thrown on |
|---|---|
|
When the default resource cannot allocate, only for an IRI whose mapped URI exceeds 1,024 octets. |
Return Value
-
parse(s, grammar::iri_rule).has_value(). -
parse(s, grammar::iri_rule_t{&resource}).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
resource |
Where the mapped copy of a long non-ASCII IRI is allocated; an ASCII IRI never reaches it. |
See Also
"URIs and IRIs", in the guide.
webcpp::lexical::is_iri
Whether s is an RFC 3987 IRI, JSON Schema’s iri.
Exceptions
| Name | Thrown on |
|---|---|
|
When the default resource cannot allocate, only for an IRI whose mapped URI exceeds 1,024 octets. |
Return Value
parse(s, grammar::iri_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"URIs and IRIs", in the guide.
webcpp::lexical::is_iri
Whether s is an RFC 3987 IRI, a mapped URI beyond 1,024 octets taken from resource.
Synopsis
Declared in <webcpp/lexical/uri.hpp>
[[nodiscard]]
bool
is_iri(
std::string_view s,
std::pmr::memory_resource& resource);
Exceptions
| Name | Thrown on |
|---|---|
|
When |
Return Value
parse(s, grammar::iri_rule_t{&resource}).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
resource |
Where the mapped copy of a long non-ASCII IRI is allocated; an ASCII IRI never reaches it. |
See Also
"URIs and IRIs", in the guide.
webcpp::lexical::is_iri_reference
is_iri_reference overloads
Synopses
Declared in <webcpp/lexical/uri.hpp>
Whether s is an RFC 3987 IRI-reference, JSON Schema’s iri-reference.
[[nodiscard]]
bool
is_iri_reference(std::string_view s);
Whether s is an RFC 3987 IRI-reference, a mapped URI beyond 1,024 octets taken from resource.
[[nodiscard]]
bool
is_iri_reference(
std::string_view s,
std::pmr::memory_resource& resource);
Exceptions
| Name | Thrown on |
|---|---|
|
When the default resource cannot allocate, only for a reference whose mapped URI exceeds 1,024 octets. |
Return Value
-
parse(s, grammar::iri_reference_rule).has_value(). -
parse(s, grammar::iri_reference_rule_t{&resource}).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
resource |
Where the mapped copy of a long non-ASCII reference is allocated; an ASCII reference never reaches it. |
See Also
"URIs and IRIs", in the guide.
webcpp::lexical::is_iri_reference
Whether s is an RFC 3987 IRI-reference, JSON Schema’s iri-reference.
Synopsis
Declared in <webcpp/lexical/uri.hpp>
[[nodiscard]]
bool
is_iri_reference(std::string_view s);
Exceptions
| Name | Thrown on |
|---|---|
|
When the default resource cannot allocate, only for a reference whose mapped URI exceeds 1,024 octets. |
Return Value
parse(s, grammar::iri_reference_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"URIs and IRIs", in the guide.
webcpp::lexical::is_iri_reference
Whether s is an RFC 3987 IRI-reference, a mapped URI beyond 1,024 octets taken from resource.
Synopsis
Declared in <webcpp/lexical/uri.hpp>
[[nodiscard]]
bool
is_iri_reference(
std::string_view s,
std::pmr::memory_resource& resource);
Exceptions
| Name | Thrown on |
|---|---|
|
When |
Return Value
parse(s, grammar::iri_reference_rule_t{&resource}).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
resource |
Where the mapped copy of a long non-ASCII reference is allocated; an ASCII reference never reaches it. |
See Also
"URIs and IRIs", in the guide.
webcpp::lexical::is_json_pointer
Whether s is an RFC 6901 JSON Pointer, JSON Schema’s json-pointer.
Synopsis
Declared in <webcpp/lexical/json_pointer.hpp>
[[nodiscard]]
bool
is_json_pointer(std::string_view s) noexcept;
Return Value
parse(s, grammar::json_pointer_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"Identifiers", in the guide.
webcpp::lexical::is_regex
Whether pattern is a regular expression, JSON Schema’s regex: an ECMA-262 Pattern in u mode, with ECMAScript 2025’s modifiers and duplicate group names.
Synopsis
Declared in <webcpp/lexical/regex.hpp>
[[nodiscard]]
bool
is_regex(std::string_view pattern) noexcept;
Description
Only the syntax and the early errors are checked: the pattern is never compiled or run. A pattern that is not well-formed UTF-8 is invalid, and a NUL is a literal like any other code point. A pattern longer than max_regex_length, or nested deeper than max_regex_nesting, is answered false without being judged. Nothing is allocated, and nothing throws.
Return Value
Whether the pattern is an ECMA-262 regular expression in u mode.
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
pattern |
Any byte string. |
See Also
"Regular expressions", in the guide.
webcpp::lexical::is_relative_json_pointer
Whether s is a relative JSON Pointer, JSON Schema’s relative-json-pointer.
Synopsis
Declared in <webcpp/lexical/json_pointer.hpp>
[[nodiscard]]
bool
is_relative_json_pointer(
std::string_view s,
index_manipulation manipulation = index_manipulation::allowed) noexcept;
Return Value
parse(s, grammar::relative_json_pointer_rule_t{manipulation}).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
manipulation |
Whether an index manipulation ( |
See Also
"Identifiers", in the guide.
webcpp::lexical::is_time
Whether s is an RFC 3339 full-time, JSON Schema’s time.
Synopsis
Declared in <webcpp/lexical/date_time.hpp>
[[nodiscard]]
bool
is_time(
std::string_view s,
leap_seconds leap = leap_seconds::allowed) noexcept;
Return Value
parse(s, grammar::time_rule_t{leap}).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
leap |
Whether second 60 may be valid: |
See Also
"Dates and times", in the guide.
webcpp::lexical::is_uri
Whether s is an RFC 3986 URI, JSON Schema’s uri: a scheme, and a fragment allowed.
Synopsis
Declared in <webcpp/lexical/uri.hpp>
[[nodiscard]]
bool
is_uri(std::string_view s) noexcept;
Return Value
parse(s, grammar::uri_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"URIs and IRIs", in the guide.
webcpp::lexical::is_uri_reference
Whether s is an RFC 3986 URI-reference, JSON Schema’s uri-reference: a URI or a relative reference.
Synopsis
Declared in <webcpp/lexical/uri.hpp>
[[nodiscard]]
bool
is_uri_reference(std::string_view s) noexcept;
Return Value
parse(s, grammar::uri_reference_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"URIs and IRIs", in the guide.
webcpp::lexical::is_uri_template
Whether s is an RFC 6570 URI Template of any level, JSON Schema’s uri-template.
Synopsis
Declared in <webcpp/lexical/uri_template.hpp>
[[nodiscard]]
bool
is_uri_template(std::string_view s) noexcept;
Return Value
parse(s, grammar::uri_template_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"URI templates", in the guide.
webcpp::lexical::is_uuid
Whether s is a UUID in RFC 9562’s string form, JSON Schema’s uuid.
Synopsis
Declared in <webcpp/lexical/uuid.hpp>
[[nodiscard]]
bool
is_uuid(std::string_view s) noexcept;
Return Value
parse(s, grammar::uuid_rule).has_value().
|
Note
|
The return value should not be discarded. |
Parameters
| Name | Description |
|---|---|
s |
Any byte string. |
See Also
"Identifiers", in the guide.
webcpp::lexical::max_regex_length
The longest pattern is_regex judges, in bytes: 65,536.
Synopsis
Declared in <webcpp/lexical/regex.hpp>
inline constexpr std::size_t max_regex_length = 65536;
Description
A longer pattern is answered false without being read, which bounds the work that a hostile pattern can make the validator do.
See Also
"Regular expressions", in the guide.
webcpp::lexical::max_regex_nesting
The deepest a pattern’s groups may nest for is_regex to judge it: 32 levels of groups, lookarounds and modifiers, one inside the other.
Synopsis
Declared in <webcpp/lexical/regex.hpp>
inline constexpr std::size_t max_regex_nesting = 32;
Description
A pattern nested deeper is answered false without being judged. The validator reads a group by calling itself, and this bound limits that recursion, so that a hostile pattern cannot exhaust the stack of a WebAssembly program.
See Also
"Regular expressions", in the guide.
WEBCPP_LEXICAL_NO_EXCEPTIONS
Defined when lexical is built without exceptions: when webcpp has none (the compiler has none, or the developer defined WEBCPP_NO_EXCEPTIONS for every webcpp library), or when the developer defines it alone, to disable lexical’s in a build that has them.
Description
lexical raises no exception of its own: a validator answers false and a rule returns its error, so the macro changes nothing in it. It is provided so that a program can set it for every webcpp library alike. Only the memory an IRI function allocates may throw, and an exception lexical raised would go through boost::throw_exception.
See Also
"Errors", in the guide.
Appendix A: Unicode data
The tables of lexical’s regular expressions,
<webcpp/lexical/detail/regex_tables.hpp>, and the patterns its test
regex_v8 reads, test/regex/cases/patterns.json, are derived from the
Unicode Character Database, version 17.0.0, which Unicode, Inc.
publishes under the following notice. lexical’s code is under the Boost
Software License 1.0 alone.
UNICODE LICENSE V3 COPYRIGHT AND PERMISSION NOTICE Copyright © 1991-2026 Unicode, Inc. NOTICE TO USER: Carefully read the following legal agreement. BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. Permission is hereby granted, free of charge, to any person obtaining a copy of data files and any associated documentation (the "Data Files") or software and any associated documentation (the "Software") to deal in the Data Files or Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sell copies of the Data Files or Software, and to permit persons to whom the Data Files or Software are furnished to do so, provided that either (a) this copyright and permission notice appear with all copies of the Data Files or Software, or (b) this copyright and permission notice appear in associated Documentation. THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in these Data Files or Software without prior written authorization of the copyright holder.
Appendix B: Changelog
What changed in lexical in each version of webcpp, newest first, one line per change. "Unreleased" is what the next version brings. The release notes of every version are on webcpp’s index page.
Unreleased
webcpp 0.1.0
-
Added the library: validators and Boost.URL rules for JSON Schema’s string formats.
-
Added dates, times and durations of RFC 3339, with a leap-second policy for v1.
-
Added UUIDs, and JSON Pointers absolute and relative, with an index manipulation policy.
-
Added IP addresses, URIs and URI references through Boost.URL, faithful to RFC 3986.
-
Added IRIs and URI templates, mapped to URIs for Boost.URL within a memory resource.
-
Added host names and e-mail addresses, internationalized ones judged by webcpp::idna.
-
Added ECMA-262 patterns in u mode, checked by an allocation-free syntax validator, with Unicode 17 tables.