using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Text; using System.Threading.Tasks; namespace HC { public class TrieNode { private Dictionary children = new(); private bool _isEndOfWord; public void AddWord(string word) { if (string.IsNullOrEmpty(word)) { throw new ArgumentException("Word cannot be null or empty."); } if (this == null) { throw new NullReferenceException("TrieNode instance is null."); } var currentNode = this; foreach (var c in word) { if (!currentNode.HasChildNode(c)) { var newNode = new TrieNode(); currentNode.AddChildNode(c, newNode); } currentNode = currentNode.GetChildNode(c); } currentNode._isEndOfWord = true; } private TrieNode GetChildNode(char c) { return children.TryGetValue(c, out var childNode) ? childNode : null; } private void AddChildNode(char c, TrieNode childNode) { children.Add(c, childNode); } private bool HasChildNode(char c) { return children.ContainsKey(c); } public IEnumerator Initialize(IEnumerable sensitiveWords, Action callback) { var count = 0; foreach (var word in sensitiveWords) { AddWord(word.Trim()); count++; if (count % 10000 == 0) { yield return null; // 暂停协程一帧 } } callback?.Invoke(); } public string FilterText(string inputText) { var inputChars = inputText.ToCharArray(); var length = inputChars.Length; var resultBuilder = new StringBuilder(); for (var startIndex = 0; startIndex < length; startIndex++) { var currentNode = this; var currentIndex = startIndex; var matchedIndex = -1; while (currentIndex < length) { var currentChar = inputChars[currentIndex]; if (currentNode.HasChildNode(currentChar)) { currentNode = currentNode.GetChildNode(currentChar); if (currentNode._isEndOfWord) { matchedIndex = currentIndex; } currentIndex++; } else { break; } } if (matchedIndex != -1) { for (var i = startIndex; i <= matchedIndex; i++) { inputChars[i] = '*'; } startIndex = matchedIndex; } } resultBuilder.Append(inputChars); return resultBuilder.ToString(); } } }