private bool ParseVariants(StringTokenEnumerator itr, ParseStatus sts) { if (itr.IsDone || sts.IsError) { return(false); } bool found = false; while (!itr.IsDone) { string s = itr.Current; if (!IsVariant(s)) { break; } found = true; if (!_variants.Any()) { _variants = new List <string>(3); } _variants.Add(s); sts.ParseLength = itr.CurrentEnd; itr.MoveNext(); } return(found); }
private bool ParseExtlangs(StringTokenEnumerator itr, ParseStatus sts) { if (itr.IsDone || sts.IsError) { return(false); } bool found = false; while (!itr.IsDone) { string s = itr.Current; if (!IsExtlang(s)) { break; } found = true; if (!_extlangs.Any()) { _extlangs = new List <string>(3); } _extlangs.Add(s); sts.ParseLength = itr.CurrentEnd; itr.MoveNext(); if (_extlangs.Count == 3) { // Maximum 3 extlangs break; } } return(found); }
private bool ParseExtensions(StringTokenEnumerator itr, ParseStatus sts) { if (itr.IsDone || sts.IsError) { return(false); } bool found = false; while (!itr.IsDone) { string s = itr.Current; if (IsExtensionSingleton(s)) { int start = itr.CurrentStart; string singleton = s; StringBuilder sb = new StringBuilder(singleton); itr.MoveNext(); while (!itr.IsDone) { s = itr.Current; if (IsExtensionSubtag(s)) { sb.Append(SEP).Append(s); sts.ParseLength = itr.CurrentEnd; } else { break; } itr.MoveNext(); } if (sts.ParseLength <= start) { sts.ErrorIndex = start; sts.ErrorMessage = "Incomplete extension '" + singleton + "'"; break; } if (_extensions.Count == 0) { _extensions = new List <String>(4); } _extensions.Add(sb.ToString()); found = true; } else { break; } } return(found); }
/// <summary> /// BNF in RFC5464 /// </summary> /// <remarks> /// Language-Tag = langtag ; normal language tags /// / privateuse ; private use tag /// / grandfathered ; grandfathered tags /// /// /// langtag = language /// ["-" script] /// ["-" region] /// *("-" variant) /// *("-" extension) /// ["-" privateuse] /// /// language = 2*3ALPHA ; shortest ISO 639 code /// ["-" extlang] ; sometimes followed by /// ; extended language subtags /// / 4ALPHA ; or reserved for future use /// / 5*8ALPHA ; or registered language subtag /// /// extlang = 3ALPHA ; selected ISO 639 codes /// *2("-" 3ALPHA) ; permanently reserved /// /// script = 4ALPHA ; ISO 15924 code /// /// region = 2ALPHA ; ISO 3166-1 code /// / 3DIGIT ; UN M.49 code /// /// variant = 5*8alphanum ; registered variants /// / (DIGIT 3alphanum) /// /// extension = singleton 1*("-" (2*8alphanum)) /// /// ; Single alphanumerics /// ; "x" reserved for private use /// singleton = DIGIT ; 0 - 9 /// / %x41-57 ; A - W /// / %x59-5A ; Y - Z /// / %x61-77 ; a - w /// / %x79-7A ; y - z /// /// privateuse = "x" 1*("-" (1*8alphanum)) /// </remarks> public static LanguageTag Parse(string languageTag, ParseStatus sts) { if (sts == null) { sts = new ParseStatus(); } else { sts.Reset(); } StringTokenEnumerator itr; bool isGrandfathered = false; // Check if the tag is grandfathered if (Grandfathered.TryGetValue(new AsciiCaseInsensitiveKey(languageTag), out string[] gfmap) && gfmap != null)
private bool ParsePrivateuse(StringTokenEnumerator itr, ParseStatus sts) { if (itr.IsDone || sts.IsError) { return(false); } bool found = false; string s = itr.Current; if (IsPrivateusePrefix(s)) { int start = itr.CurrentStart; StringBuilder sb = new StringBuilder(s); itr.MoveNext(); while (!itr.IsDone) { s = itr.Current; if (!IsPrivateuseSubtag(s)) { break; } sb.Append(SEP).Append(s); sts.ParseLength = itr.CurrentEnd; itr.MoveNext(); } if (sts.ParseLength <= start) { // need at least 1 private subtag sts.ErrorIndex = start; sts.ErrorMessage = "Incomplete privateuse"; } else { _privateuse = sb.ToString(); found = true; } } return(found); }
private bool ParseRegion(StringTokenEnumerator itr, ParseStatus sts) { if (itr.IsDone || sts.IsError) { return(false); } bool found = false; string s = itr.Current; if (IsRegion(s)) { found = true; _region = s; sts.ParseLength = itr.CurrentEnd; itr.MoveNext(); } return(found); }
/// <summary> /// BNF in RFC5464 /// </summary> /// <remarks> /// Language-Tag = langtag ; normal language tags /// / privateuse ; private use tag /// / grandfathered ; grandfathered tags /// /// /// langtag = language /// ["-" script] /// ["-" region] /// *("-" variant) /// *("-" extension) /// ["-" privateuse] /// /// language = 2*3ALPHA ; shortest ISO 639 code /// ["-" extlang] ; sometimes followed by /// ; extended language subtags /// / 4ALPHA ; or reserved for future use /// / 5*8ALPHA ; or registered language subtag /// /// extlang = 3ALPHA ; selected ISO 639 codes /// *2("-" 3ALPHA) ; permanently reserved /// /// script = 4ALPHA ; ISO 15924 code /// /// region = 2ALPHA ; ISO 3166-1 code /// / 3DIGIT ; UN M.49 code /// /// variant = 5*8alphanum ; registered variants /// / (DIGIT 3alphanum) /// /// extension = singleton 1*("-" (2*8alphanum)) /// /// ; Single alphanumerics /// ; "x" reserved for private use /// singleton = DIGIT ; 0 - 9 /// / %x41-57 ; A - W /// / %x59-5A ; Y - Z /// / %x61-77 ; a - w /// / %x79-7A ; y - z /// /// privateuse = "x" 1*("-" (1*8alphanum)) /// </remarks> public static LanguageTag Parse(string languageTag, ParseStatus sts) { if (sts == null) { sts = new ParseStatus(); } else { sts.Reset(); } StringTokenEnumerator itr; bool isGrandfathered = false; // Check if the tag is grandfathered string[] gfmap; if (GRANDFATHERED.TryGetValue(new AsciiUtil.CaseInsensitiveKey(languageTag), out gfmap) && gfmap != null) { // use preferred mapping itr = new StringTokenEnumerator(gfmap[1], SEP); isGrandfathered = true; } else { itr = new StringTokenEnumerator(languageTag, SEP); } // ICU4N: Move to the first element itr.MoveNext(); LanguageTag tag = new LanguageTag(); // langtag must start with either language or privateuse if (tag.ParseLanguage(itr, sts)) { tag.ParseExtlangs(itr, sts); tag.ParseScript(itr, sts); tag.ParseRegion(itr, sts); tag.ParseVariants(itr, sts); tag.ParseExtensions(itr, sts); } tag.ParsePrivateuse(itr, sts); if (isGrandfathered) { // Grandfathered tag is replaced with a well-formed tag above. // However, the parsed length must be the original tag length. Debug.Assert(itr.IsDone); Debug.Assert(!sts.IsError); sts.ParseLength = languageTag.Length; } else if (!itr.IsDone && !sts.IsError) { string s = itr.Current; sts.ErrorIndex = itr.CurrentStart; if (s.Length == 0) { sts.ErrorMessage = "Empty subtag"; } else { sts.ErrorMessage = "Invalid subtag: " + s; } } return(tag); }