let parse_tag_value s =
let parse_tag s =
if (String.length s = 2)
&& (match s.[0] with 'A' .. 'Z' | 'a' .. 'z' -> true | _ -> false)
&& (match s.[1] with
| 'A' .. 'Z' | 'a' .. 'z' | '0' .. '9' -> true
| _ -> false
)
then
Ok s
else
error "invalid tag" s sexp_of_string
in
let parse_value tag s =
if (s <> "")
&& (String.for_all s ~f:(function ' ' .. '~' -> true | _ -> false))
then
Ok s
else
error "tag has invalid value" (tag,s)
<:sexp_of< string * string >>
in
match String.lsplit2 s ~on:':' with
| None ->
error "tag-value not colon separated" s sexp_of_string
| Some (tag,value) ->
parse_tag tag >>= fun tag ->
parse_value tag value >>= fun value ->
Ok (tag, value)