mult = (ip / mac / doc_id / url / email / ipv6 / phonenumber / unit / wifi / tech_prot / date / any)+
any = ~r"(.|\s)+?(?=((?<=[\s\"\”(])|^).)" / ~r"(.|\s)+"
pre = ~r"((?<=[\s\"\”(])|^)"
post = ~r"(?=(([.,\"\”])|\),?)\s|\s|$)"
space = " "
dash = "-"
zero = "0"
one = "1"
onetotwo = ~"[1-2]"
onetonine = ~"[1-9]"
digit = ~"[0-9]"
num = twofifty / twohun / hun / tens
twofifty = ~"25[0-5]"
twohun = ~"2[0-4][0-9]"
hun = one digit{2}
tens = ~"[1-9]?[0-9]"
blocks = ~r"/(0|[1-9][0-9]?)"
ipv4_raw = (num "."){3} num blocks?

ip = pre ipv4_raw post

mac = pre (dotMAC / colonMAC / hyphenMAC) post
dotMAC = (alnum{4} "."){2} alnum{4}
colonMAC = (alnum{2} ":"){5} alnum{2}
hyphenMAC = (alnum{2} "-"){5} alnum{2}
alnum = ~"[a-fA-F0-9]"

doc_id = pre (memo / report) post
memo = "FOI Memo " four_digits
report = "FOI" "-" letter "--" four_digits "--SE"
letter = ~"[A-Z]"
four_digits = digit{4}

url = pre preamble host (path)? (query)? (fragment)? post
preamble = (protocol "www.") / protocol / "www."
host = (validhostname "." host) / (validhostname port) / (validhostname "." tld) / "localhost"
validhostname = (validhostchar)+ ("-" (validhostchar)+)*
tld = "com" / "se" / "io" / "nu" / "fi" / "no" / "org" / "dk" / "dev" / "net" / "co" / "co.uk" / "de" / "yes"
port = ":" portnr
portnr = digit{1,4}
path = "/" (validpathchar)* (path)*
validpathchar = ~r"[a-zA-Z0-9-\.]"
query = "?" queryparams
queryparams = (validhostchar)+ "=" (validhostchar)+ ("&" queryparams)*
fragment = "#" (fragmentchar)+
fragmentchar = ~r"[a-zA-Z0-9]"
validhostchar = ~r"[a-zA-Z0-9]"
protocol = scheme "://"
scheme = "http" ("s")?

email = pre (local email_domain1) post
local = local_char (dotordash local_char)* "@"
local_char = ~r"[\w!#$%&'*\-+/=?^`{|}~]+"
email_domain1 = ~r"([A-Za-z0-9-]+\.)+[A-Za-z]{2,7}"
dotordash = "." / "-"

ipv6 = pre (ipv4_embedded / ipv4_mapped / fe80 / base_ipv6 / comp) blocks? post
comp = compressed7 / compressed6 / compressed5 / compressed4 / compressed3 / compressed2 / compressed1 / compressed0
base_ipv6 = oct_col{7} octet
compressed0 = oct_col{1,7} colon
compressed1 = oct_col{1,6} col_oct
compressed2 = oct_col{1,5} col_oct{1,2}
compressed3 = oct_col{1,4} col_oct{1,3}
compressed4 = oct_col{1,3} col_oct{1,4}
compressed5 = oct_col{1,2} col_oct{1,5}
compressed6 = oct_col col_oct{1,6}
compressed7 = colon (col_oct{1,7} / colon)
fe80 = "fe80" colon col_oct{0,4} ~"%[0-9a-zA-Z]+"
ipv4_mapped = colon colon ("ffff" (colon zero{1,4})? colon)? ipv4_raw
ipv4_embedded = oct_col{1,4} colon ipv4_raw
oct_col = octet colon
col_oct = colon octet
octet = ~r"[0-9A-Fa-f]{1,4}"
colon = ":"

phonenumber = pre pn_prefix ((&(ten_digit post) ten_digit) / (&(nine_digit post) nine_digit) / eight_digit) post
ten_digit = ten_1 / ten_2 / ten_3
nine_digit = nine_1 / nine_2 / nine_3
eight_digit = eight_1 / eight_2
ten_1 = eightdash digit{3} space digit{3} space digit{2}
ten_2 = digit{2} dash digit{3} space digit{2} space digit{2}
ten_3 = digit{3} dash digit{2} space digit{2} space digit{2}
nine_1 = eightdash digit{3} space digit{2} space digit{2}
nine_2 = digit{2} dash digit{2} space digit{2} space digit{2}
nine_3 = digit{3} dash digit{3} space digit{2}
eight_1 = eightdash digit{2} space digit{2} space digit{2}
eight_2 = digit{2} dash digit{3} space digit{2}
pn_prefix = "0" / ((long_pre &(ten_digit / nine_digit / eight_digit)) / pre_digits)
pre_digits = ~r"\+[1-9][0-9]?"
long_pre = ~r"\+[1-9][0-9]{2}"
eightdash = "8-"

unit = pre (speed_dim / val_unit / len_dim / sound_dim) post
val_unit = val " " ((prefixes? si_units) / (data_prefixes? data_units) / no_pre_units)
len_dim = val (dim_sep val){0,2} " " ((prefixes? "m") / "m")
sound_dim = (negativeval / val) " " ("dBm" / "dB")
speed_dim = val " " ("m/s")
dim_sep = ~r" x |x|\*| \* "
no_pre_units = ~"[sK]|°C"
si_units = "Hz" / "Watt" / "Wh" / "W" / "g" / "J" / "N" / "V" / "A" / "Ω"
data_units = ~"(B|b(it)?)([/p]s)?"
data_prefixes = ~"[kMGTPEZYRQ]i?"
prefixes = ~"[qryzafpnµmcdkMGTPEZYRQ]"
numval = int_val deci_val?
negativeval = "-" numval
val = range / numval
range = numval "-" numval
int_val = (onetonine digit{0,3}) / zero
deci_val = ~r"[.,]\d{1,5}"

wifi = pre wifi_fam (version ("/" version)*)? post
wifi_fam = "802.11"
version = ~"[cdefghijkmnprsTuvwyz]|a[cdfhijkqx]?|be?"

date = pre (leap_date / date_in / date_swe) post
leap_date = ("29 februari " leap_year) / (leap_year "-02-29")
date_swe = swe_num / swe_text
swe_text = ((thirtyone " " mon31_text) / (thirty " " mon30_text) / (twenty8 " februari")) " " year
swe_num = ((thirty "/" mon30_num) / (thirtyone "/" mon31_num) / (twenty8 "/2")) " " year
date_in = year "-" ((mon31_num0 "-" thirtyone0) / (mon30_num0 "-" thirty0) / ("02-" twenty80))
thirtyone = ~"[1-2][0-9]|3[0-1]|[1-9]"
thirty = ~"[1-2][0-9]|30|[1-9]"
thirtyone0 = ~"0[1-9]|[1-2][0-9]|3[0-1]"
thirty0 = ~"0[1-9]|[1-2][0-9]|30"
twenty8 = ~"1[0-9]|2[0-8]|[1-9]"
twenty80 = ~"0[1-9]|1[0-9]|2[0-8]"
year = ~"(19|20)[0-9]{2}"
leap_year = ~"19(0[48]|[2468][048]|[13579][26])|20([02468][048]|[13579][26])"
mon31_num0 = ~r"0[13578]|1[02]"
mon30_num0 = ~r"0[469]|11"
mon31_num = ~r"1[02]|[13578]"
mon30_num = ~r"11|[469]"
mon31_text = "januari" / "mars" / "maj" / "juli" / "augusti" / "oktober" / "december"
mon30_text = "april" / "juni" / "september" / "november"

tech_prot = (pre (tech / prot) tp_post) / ipaddr
tech = eth / wifi_str / rj45 / bt  / cat 
prot = uart / ssh / http / mac_str / uri / transmission / dns / telnet / mqtt / amqp
ipaddr = pre ~"IP(v[46]|[- ][aA]dd?ress)?" post
telnet = ~"[Tt]elnet"
dns = "DNS" / "dns"
transmission = ("TC" / "UD" / "FT") "P"
uri = ~"UR[IL]|ur[il]"
cat = ~"CAT[1-8]"
mac_str = "MAC"
bt = ~"[Bb]luetooth|BLUETOOTH"
http = ~"https?|HTTPS?"
ssh = "ssh" / "SSH"
uart = "UART"
rj45 = "RJ45"
wifi_str = ~"Wi-?Fi|[Ww]i-?fi"
eth = ~"[Ee]thernet|ETHERNET"
mqtt = ~"[Mm]qtt|MQTT"
amqp = ~"[Aa]mqp|AMQP"
tp_post = post / &("-")

