/* * Copyright (c) 2014-2017, Eren Okka * Copyright (c) 2016-2017, Paul Miller * Copyright (c) 2017-2018, Tyler Bratton * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ using System; using System.Collections.Generic; using System.Linq; namespace AnitomySharp { /// /// An anime filename is tokenized into individual s. This class represents an individual token. /// /// 动画文件名被标记化为单一的标记(token) /// public class Token { /// /// The category of the token. /// /// 标记(token)类型 /// public enum TokenCategory { /// /// 未知类型, /// /// 包括:无括号/分隔符的字符串;分隔符分割后的字符串 /// Unknown, /// /// 括号 /// Bracket, /// /// 分隔符,包括Options.AllowedDelimiters /// Delimiter, /// /// 标识符,包括关键词(一眼真keyword被添加到token) /// Identifier, /// /// 无效,错误的标记,不会出现在最后的标记(token)列表中。比如在验证分隔符切分的标记时,规则匹配到的无效标记(token) /// Invalid } /// /// TokenFlag, used for searching specific token categories. This allows granular searching of TokenCategories. /// /// 标记符,用于细粒度搜索特定的标记类型()。 /// public enum TokenFlag { /// /// None 无 /// FlagNone, // Categories /// /// 括号符 /// FlagBracket, /// /// /// FlagNotBracket, /// /// 分隔符 /// FlagDelimiter, /// /// /// FlagNotDelimiter, /// /// 标识符 /// FlagIdentifier, /// /// /// FlagNotIdentifier, /// /// 未知 /// FlagUnknown, /// /// /// FlagNotUnknown, /// /// 有效 /// FlagValid, /// /// /// FlagNotValid, // Enclosed (Meaning that it is enclosed in some bracket (e.g. [ ] )) /// /// 闭合符 /// FlagEnclosed, /// /// 未闭合符 /// FlagNotEnclosed } /// /// Set of token category flags /// /// 标识符分类列表 /// private static readonly List FlagMaskCategories = new List { TokenFlag.FlagBracket, TokenFlag.FlagNotBracket, TokenFlag.FlagDelimiter, TokenFlag.FlagNotDelimiter, TokenFlag.FlagIdentifier, TokenFlag.FlagNotIdentifier, TokenFlag.FlagUnknown, TokenFlag.FlagNotUnknown, TokenFlag.FlagValid, TokenFlag.FlagNotValid }; /// /// Set of token enclosed flags /// /// 闭合的标识符列表 /// private static readonly List FlagMaskEnclosed = new List { TokenFlag.FlagEnclosed, TokenFlag.FlagNotEnclosed }; /// /// 标记的类型 /// public TokenCategory Category { get; set; } /// /// 标记的内容 /// public string Content { get; set; } /// /// 标记是否被括号包裹 /// public bool Enclosed { get; } /// /// Constructs a new token /// /// 构造一个新的标记(token) /// /// the token category /// whether or not the token is enclosed in braces /// the token content public Token(TokenCategory category, bool enclosed, string content) { Category = category; Enclosed = enclosed; Content = content; } /// /// Validates a token against the flags. The flags is used as a search parameter. /// /// 验证传入的标记(token)是否满足标记符(flag) /// /// the token /// the flags the token must conform against /// true if the token conforms to the set of flags; false otherwise private static bool CheckTokenFlags(Token token, ICollection flags) { // Simple alias to check if flag is a part of the set bool CheckFlag(TokenFlag flag) { return flags.Contains(flag); } // Make sure token is the correct closure if (flags.Any(f => FlagMaskEnclosed.Contains(f))) { var success = CheckFlag(TokenFlag.FlagEnclosed) == token.Enclosed; if (!success) return false; // Not enclosed correctly (e.g. enclosed when we're looking for non-enclosed). } // Make sure token is the correct category if (!flags.Any(f => FlagMaskCategories.Contains(f))) return true; var secondarySuccess = false; void CheckCategory(TokenFlag fe, TokenFlag fn, TokenCategory c) { if (secondarySuccess) return; var result = CheckFlag(fe) ? token.Category == c : CheckFlag(fn) && token.Category != c; secondarySuccess = result; } CheckCategory(TokenFlag.FlagBracket, TokenFlag.FlagNotBracket, TokenCategory.Bracket); CheckCategory(TokenFlag.FlagDelimiter, TokenFlag.FlagNotDelimiter, TokenCategory.Delimiter); CheckCategory(TokenFlag.FlagIdentifier, TokenFlag.FlagNotIdentifier, TokenCategory.Identifier); CheckCategory(TokenFlag.FlagUnknown, TokenFlag.FlagNotUnknown, TokenCategory.Unknown); CheckCategory(TokenFlag.FlagNotValid, TokenFlag.FlagValid, TokenCategory.Invalid); return secondarySuccess; } /// /// Given a list of tokens, searches for any token token that matches the list of flags. /// /// the list of tokens /// the search starting position. /// the search ending position. /// the search flags /// the search result public static int FindToken(List tokens, int begin, int end, params TokenFlag[] flags) { return FindTokenBase(tokens, begin, end, i => i < tokens.Count, i => i + 1, flags); } /// /// Given a list of tokens, searches for the next token in tokens that matches the list of flags. /// /// the list of tokens /// the search starting position. /// the search flags /// the search result public static int FindNextToken(List tokens, int first, params TokenFlag[] flags) { return FindTokenBase(tokens, first + 1, tokens.Count, i => i < tokens.Count, i => i + 1, flags); } /// /// Given a list of tokens, searches for the previous token in tokens that matches the list of flags. /// /// 在给定的标记列表中搜索匹配输入的标记符前一个标记 /// /// the list of tokens /// the search starting position. Exclusive of position.Pos /// the search flags /// the search result public static int FindPrevToken(List tokens, int begin, params TokenFlag[] flags) { return FindTokenBase(tokens, begin - 1, -1, i => i >= 0, i => i - 1, flags); } /// /// Given a list of tokens finds the first token that passes . /// /// 在给定的标记列表中找到第一个通过的标记(token) /// /// the list of the tokens to search /// the start index of the search. /// the end index of the search. /// a function that returns whether or not we should continue searching /// a function that returns the next search index /// the flags that each token should be validated against /// the found token private static int FindTokenBase( List tokens, int begin, int end, Func shouldContinue, Func next, params TokenFlag[] flags) { var find = new List(); find.AddRange(flags); for (var i = begin; shouldContinue(i); i = next(i)) { var token = tokens[i]; if (CheckTokenFlags(token, find)) { return i; } } return end; } /// /// /// /// /// /// public static bool InListRange(int pos, List list) { return -1 < pos && pos < list.Count; } /// /// /// /// /// public override bool Equals(object o) { if (this == o) return true; if (!(o is Token)) return false; var token = (Token)o; return Enclosed == token.Enclosed && Category == token.Category && Equals(Content, token.Content); } /// /// /// /// public override int GetHashCode() { var hashCode = -1776802967; hashCode = hashCode * -1521134295 + Category.GetHashCode(); hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Content); hashCode = hashCode * -1521134295 + Enclosed.GetHashCode(); return hashCode; } /// /// /// /// public override string ToString() { return $"Token{{category={Category}, content='{Content}', enclosed={Enclosed}}}"; } } }