using System; using System.Collections.Generic; namespace ET.PackageManager.Editor { [Serializable] public struct StrChunk { /// /// 字符串,或者key /// 如果是字符串,keyIndex = 0; /// 如果是key,keyIndex表示索引,从1开始 /// public string TextOrKey; /// /// 如果StrOrKey为Key时的索引值,从1开始 /// public byte KeyIndex; } public static partial class StrUtil { /// /// 高性能处理字符串中{%key%num}形式的占位符 /// 其中key为连续的小写字母,nul为非0开头的连续数字 /// 返回一个StrChunk数组,方便使用的地方缓存以加速替换占位符 /// /// /// /// 是否抛出错误 /// 如果为false,则会进行容错性解析 /// /// public static StrChunk[] GetStrChunk(string value, bool throwError = false) { if (string.IsNullOrEmpty(value)) { return Array.Empty(); } var chunks = g_cacheStrChunkList; var sb = SbPool.Get(); var keySb = SbPool.Get(); var indexSb = SbPool.Get(); int throwErrId = -1; char lastChar = char.MaxValue; ReadChunkState state = ReadChunkState.ReadText; const char beginChar = '{'; const char endChar = '}'; int chrCount = value.Length; for (int i = 0; i < chrCount; i++) { char c = value[i]; switch (state) { case ReadChunkState.ReadText: switch (c) { case beginChar: state = ReadChunkState.ReadyReadKey; break; case endChar: state = ReadChunkState.Escape; break; default: sb.Append(c); break; } break; case ReadChunkState.ReadyReadKey: if (c == beginChar) { //{{,转义为{ sb.Append(beginChar); state = ReadChunkState.ReadText; break; } if (c < 'a' || c > 'z') { throwErrId = 1; sb.Append(beginChar).Append(c); state = ReadChunkState.ReadText; break; } keySb.Append(c); state = ReadChunkState.ReadKey; break; case ReadChunkState.ReadKey: if (c >= 'a' && c <= 'z') { keySb.Append(c); break; } if (c >= '1' && c <= '9') { indexSb.Append(c); state = ReadChunkState.ReadIndex; break; } throwErrId = 2; sb.Append(beginChar).Append(keySb.ToString()).Append(c); keySb.Clear(); state = ReadChunkState.ReadText; break; case ReadChunkState.ReadIndex: if (c >= '0' && c <= '9') { indexSb.Append(c); break; } if (c == endChar) { chunks.Add(new StrChunk() { TextOrKey = sb.ToString() }); chunks.Add(new StrChunk() { KeyIndex = byte.Parse(indexSb.ToString()), TextOrKey = keySb.ToString() }); sb.Clear(); } else { throwErrId = 3; sb.Append(beginChar) .Append(keySb.ToString()) .Append(indexSb.ToString()) .Append(c); } keySb.Clear(); indexSb.Clear(); state = ReadChunkState.ReadText; break; case ReadChunkState.Escape: if (c == lastChar) { sb.Append(c); } else { throwErrId = 0; sb.Append(lastChar).Append(c); } state = ReadChunkState.ReadText; break; } //处理错误 if (throwError && throwErrId > -1) { switch (throwErrId) { case 0: throw new Exception(string.Format("text={3}, index={0}, chr='{1}':此处只能出现'{2}'", i, c, lastChar, value)); case 1: throw new Exception(string.Format("text={2}, index={0}, chr='{1}', 此处只能出现小写英文字符", i, c, value)); case 2: throw new Exception(string.Format("text={2}, index={0}, chr='{1}', 此处只能出现小写英文或1-9的数字", i, c, value)); case 3: throw new Exception(string.Format("text={2}, index={0}, chr='{1}', 0-9的数字或'}}'", i, c, value)); } } lastChar = c; } //结尾处理 if (state != ReadChunkState.ReadText) { if (throwError) { throw new Exception("没有正确结束, state=" + state.ToString()); } sb.Append(keySb.ToString()).Append(indexSb.ToString()); } if (sb.Length > 0) { chunks.Add(new StrChunk() { TextOrKey = sb.ToString() }); } SbPool.Put(sb); SbPool.Put(keySb); SbPool.Put(indexSb); var arr = chunks.ToArray(); chunks.Clear(); return arr; } private static readonly List g_cacheStrChunkList = new List(); private enum ReadChunkState { ReadText, ReadyReadKey, ReadKey, ReadIndex, //转义处理 Escape } } }