public static (bool Valid, string Message) IsDocumentIdValid(this string documentId) { const string syntax = "[{container}:]{path}[/{path}...]"; if (documentId.IsEmpty()) { return(false, "Id required"); } IReadOnlyList <IToken> tokens = new StringTokenizer() .Add(":", "/") .Parse(documentId); int containerSymbolCount = tokens.Count(x => x.Value == ":"); if (containerSymbolCount > 1) { return(false, $"Invalid container, cannot have more then one ':', {syntax}"); } if (containerSymbolCount == 1 && (tokens.Count <= 1 || tokens[1].Value != ":")) { return(false, $"Invalid container, {syntax}"); } if (containerSymbolCount == 0 && tokens.Where(filterSyntax).Count() == 0) { return(false, $"No path, {syntax}"); } if (tokens.Last().Value == ":") { return(false, $"Cannot end with ':', {syntax}"); } if (tokens.Last().Value == "/") { return(false, $"Cannot end with '/', {syntax}"); } string?error = tokens .Where(filterSyntax) .Select(x => testVector(x.Value)) .FirstOrDefault(x => x != null); return(error != null ? (false, error) : (true, String.Empty));