using System.Collections.Generic;
using System.Text.RegularExpressions;
public static void Main()
Console.WriteLine("Hello World");
foreach (var keyword in KeywordGroup.CreateFromRawString("Test \"Hello World\" or1 OR or2 OR or or3 and1 and2"))
Console.WriteLine($"{keyword.CombineMode}: {string.Join(", ", keyword.Words)}");
internal record KeywordGroup(IEnumerable<KeywordItem> Words, CombineMode CombineMode, bool InQuotes)
public static IEnumerable<KeywordGroup> CreateFromRawString(string? searchQuery)
if (searchQuery is not { Length: > 0 }) yield break;
var matches = Regex.Matches(searchQuery, @"(?:[^\s""]+|""[^""]*"")+");
var words = matches.Select(match => match.Value).ToArray();
var combineMode = CombineMode.And;
var wordsBuffer = new List<KeywordItem>();
foreach (var (current, index) in words.Select((x, i) => (x, i)))
var equalsOr = (string v) => v.Equals("OR", StringComparison.OrdinalIgnoreCase);
if (current is not { Length: > 0 } || equalsOr(current))
inQuotes = Regex.IsMatch(current, @"""[^""]*""");
? (equalsOr(words[index + 1]) ? CombineMode.OrElse : CombineMode.And)
var currentWord = new KeywordItem(current.Trim('"'), inQuotes);
if (combineMode == nextCombineMode)
wordsBuffer.Add(currentWord);
yield return new(wordsBuffer, combineMode, inQuotes);
wordsBuffer = new() { currentWord };
yield return new(wordsBuffer.Append(currentWord), combineMode, inQuotes);
combineMode = nextCombineMode;
yield return new(wordsBuffer, combineMode, inQuotes);
public record KeywordItem(string Value, bool InQuotes);
internal enum CombineMode