|
|
@@ -1,4 +1,5 @@
|
|
|
#pragma once
|
|
|
+#include <cstdio>
|
|
|
#include <jvalidate/_macro.h>
|
|
|
|
|
|
#include <cctype>
|
|
|
@@ -49,6 +50,12 @@ template <typename CharT = char> bool email(std::basic_string_view<CharT> em);
|
|
|
}
|
|
|
|
|
|
namespace jvalidate::format::detail {
|
|
|
+inline bool is_dec(std::string_view s, size_t min = 0, size_t max = std::string_view::npos) {
|
|
|
+ constexpr char const * g_dec_digits = "0123456789";
|
|
|
+ return s.find_first_not_of(g_dec_digits) == std::string::npos && s.size() >= min &&
|
|
|
+ s.size() <= max;
|
|
|
+}
|
|
|
+
|
|
|
inline bool is_hex(std::string_view s) {
|
|
|
constexpr char const * g_hex_digits = "0123456789ABCDEFabcdef";
|
|
|
return s.find_first_not_of(g_hex_digits) == std::string::npos;
|
|
|
@@ -248,6 +255,9 @@ inline bool utc_millisec(std::string_view utc) {
|
|
|
}
|
|
|
|
|
|
inline bool css_2_1_color(std::string_view color) {
|
|
|
+ if (color.empty()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
constexpr char const * g_hex_digits = "0123456789ABCDEFabcdef";
|
|
|
if (color[0] == '#') {
|
|
|
return color.size() <= 7 && detail::is_hex(color.substr(1));
|
|
|
@@ -257,6 +267,24 @@ inline bool css_2_1_color(std::string_view color) {
|
|
|
"green", "navy", "blue", "aqua", "teal", "black", "silver", "gray"};
|
|
|
return g_color_codes.contains(color);
|
|
|
}
|
|
|
+
|
|
|
+inline bool e_123_phone(std::string_view phone) {
|
|
|
+ // https://support.secureauth.com/hc/en-us/articles/360036402211-Regular-Expressions-for-ITU-E-123-and-E-164-phone-number-formats
|
|
|
+ if (phone.empty()) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (phone[0] != '+') {
|
|
|
+ constexpr size_t g_usa_phone_tokens = 3;
|
|
|
+ char area[4], head[4], tail[5];
|
|
|
+ return sscanf(phone.data(), "(%3s) %3s %4s", area, head, tail) == g_usa_phone_tokens &&
|
|
|
+ detail::is_dec(area, 3) && detail::is_dec(head, 3) && detail::is_dec(tail, 4);
|
|
|
+ }
|
|
|
+ char tok0[4], tok1[4], tok2[4], tok3[5];
|
|
|
+ constexpr size_t g_i18n_phone_tokens = 4;
|
|
|
+ return sscanf(phone.data(), "+%3s %3s %3s %4s", tok0, tok1, tok2, tok3) == g_i18n_phone_tokens &&
|
|
|
+ detail::is_dec(tok0, 1, 3) && detail::is_dec(tok1, 2, 3) && detail::is_dec(tok2, 2, 3) &&
|
|
|
+ detail::is_dec(tok3, 4);
|
|
|
+}
|
|
|
}
|
|
|
|
|
|
namespace jvalidate::format {
|
|
|
@@ -715,7 +743,7 @@ private:
|
|
|
{"utc-millisec", &format::draft03::utc_millisec},
|
|
|
{"color", &format::draft03::css_2_1_color},
|
|
|
{"style", nullptr},
|
|
|
- {"phone", nullptr},
|
|
|
+ {"phone", &format::draft03::e_123_phone},
|
|
|
{"uri", &format::uri},
|
|
|
{"email", &format::email},
|
|
|
{"ip-address", &format::ipv4},
|