/*
* 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}}}";
}
}
}