Логические выражения для поиска в строке ( hello OR hi) AND world - C#
Формулировка задачи:
Может кто-то видел готовые библиотеки?
хотелось бы что-то пожирней и без напильника в комплекте
чтоб например изменять ключевые слова (ИЛИ И НЕ -- || && !), оба регистра кушала, с кавычками дружила, ошибки обходила и всяческие мелкие тонкости?
поисковики не понимают о чем речь
c# and not(VB or SQL)
Решение задачи: «Логические выражения для поиска в строке ( hello OR hi) AND world»
textual
Листинг программы
[Serializable] public class StringExpression { private const string LBracket = "("; private const string RBracket = ")"; private static Regex _splitRegex = new Regex(@"\b|(?<=[!&'""\(\)])|(?=[!&'""\(\)])", RegexOptions.Compiled); private static Dictionary<TokenType, byte> _prio = new Dictionary<TokenType, byte> { {TokenType.OR, 1}, {TokenType.AND, 2}, {TokenType.NOT, 3}, //{TokenType.QUOTE, 4}, }; private static Dictionary<TokenType, List<string>> _keyWords = new Dictionary<TokenType, List<string>> { {TokenType.OR, new List<string>(3) {"OR", "|", "ИЛИ"}}, {TokenType.AND, new List<string>(3) {"AND", "&", "И"}}, {TokenType.NOT, new List<string>(3) {"NOT", "!", "НЕ"}}, {TokenType.Quote, new List<string>(3) {"\"", "'"}}, {TokenType.LBracket, new List<string>(1) {LBracket}}, {TokenType.RBracket, new List<string>(1) {RBracket}}, }; private string originExpression; private bool ignoreCase; private bool fullWords; [XmlAttribute("IgnoreCase")] public bool IgnoreCase { get { return ignoreCase; } set { ignoreCase = value; } } [XmlAttribute("FullWords")] public bool FullWords { get { return fullWords; } set { fullWords = value; } } [XmlAttribute("Expression")] public string Expression { get { return originExpression; } set { originExpression = value; tokenizedExpression = null; } } public StringExpression() :this(null) { } public StringExpression(string expression, bool ignoreCase = true, bool fullWords = false) { this.fullWords = fullWords; IgnoreCase = ignoreCase; Expression = expression; } private List<string> tokenizedExpression; private IEnumerable<string> Tokenized { get { if (tokenizedExpression == null) { tokenizedExpression = ToPostFix(originExpression); } return tokenizedExpression; } } protected virtual List<string> ToPostFix(string sourceString) { if (string.IsNullOrEmpty(sourceString)) return new List<string>(0); string[] tokens = _splitRegex.Split(sourceString); if (tokens.Length == 1) return new List<string>(1) { tokens[0] }; var result = new List<string>(); var stack = new Stack<string>(); bool isEscapedData = false; var quotedData = new StringBuilder(); foreach (string rawToken in tokens) { if (string.IsNullOrEmpty(rawToken)) continue; var token = rawToken.Trim().ToUpper(); TokenType typeToken = GetTokenType(token); if (isEscapedData) { if (typeToken == TokenType.Quote) { result.Add(quotedData.ToString()); quotedData.Length = 0; isEscapedData = false; } else { quotedData.Append(rawToken); } } else { if (StringExt.IsNullOrWhiteSpace(token)) continue; switch (typeToken) { case TokenType.AND: case TokenType.NOT: case TokenType.OR: while (stack.Count > 0) { string topToken = stack.Peek(); if (_prio.ContainsKey(GetTokenType(topToken)) && _prio[typeToken] < _prio[GetTokenType(topToken)]) { result.Add(stack.Pop()); } else { break; } result.Add(stack.Pop()); } stack.Push(token); break; case TokenType.LBracket: stack.Push(rawToken); break; case TokenType.RBracket: if (stack.Count <= 0) throw new Exception("Некорректное выражение"); string op = stack.Pop(); while (op != LBracket) { result.Add(op); if (stack.Count <= 0) throw new Exception("Некорректное количевство скобок"); op = stack.Pop(); } break; case TokenType.Quote: isEscapedData = true; break; default: result.Add(rawToken); break; } } } if (isEscapedData) { throw new Exception("Кавычка не закрыта"); } foreach (string symbol in stack) { result.Add(symbol); } return result; } public virtual bool IsMatch(string text) { if (text == null) throw new ArgumentNullException("text"); var stackResult = new Stack<bool>(); if (!Tokenized.Any()) return true; foreach (var token in Tokenized) { if (StringExt.IsNullOrWhiteSpace(token)) continue; bool left; bool right; switch (GetTokenType(token)) { case TokenType.AND: left = stackResult.Pop(); right = stackResult.Pop(); stackResult.Push(left && right); break; case TokenType.NOT: left = stackResult.Pop(); stackResult.Push(!left); break; case TokenType.OR: left = stackResult.Pop(); right = stackResult.Pop(); stackResult.Push(left || right); break; case TokenType.LBracket: break; case TokenType.RBracket: break; case TokenType.Quote: break; default: bool exists; if (fullWords) { exists = Regex.IsMatch(text, @"\b" + token + @"\b", ignoreCase ? RegexOptions.IgnoreCase : RegexOptions.None); } else { exists = text.IndexOf(token, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) >= 0; } stackResult.Push(exists); break; } } if (stackResult.Count != 1) { throw new Exception("Ошибки при использовании выражения"); } return stackResult.Pop(); } private TokenType GetTokenType(string token) { if (StringExt.IsNullOrWhiteSpace(token)) return TokenType.String; foreach (var keyWord in _keyWords) { if (keyWord.Value.Contains(token)) { return keyWord.Key; } } return TokenType.String; } public enum TokenType { NOT, AND, OR, LBracket, RBracket, Quote, String } private static class StringExt { public static bool IsNullOrWhiteSpace(string str) { if (string.IsNullOrEmpty(str)) return true; for (int i = 0; i < str.Length; i++) { if (!char.IsWhiteSpace(str[i])) { return false; } } return true; } } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д