/// <summary> /// 快速原子分词,将连续的同类型的字符作为一个AtomNode /// 对浮点数做了特殊处理 /// </summary> /// <param name="chars"></param> /// <param name="start">起始位置,inclusive</param> /// <param name="end">截止位置,exclusive</param> /// <returns></returns> protected static List <AtomNode> QuickAtomSegment(char[] chars, int start, int end) { var atoms = new List <AtomNode>(); var cursor = start; int preType = CharType.Get(chars[cursor++]); // 获取首个字符类型 int curType; while (cursor < end) // 从第二个字符开始,将连续类型的字符组成的字符串作为一个整体,构建一个原子节点对象 { curType = CharType.Get(chars[cursor]); if (curType != preType) // 如果收到前后相邻字符的类型不一致 { if (chars[cursor] == '.' && preType == CT_NUM) // 浮点数识别 { cursor++; // 指向 dot 符号的下一个符号 while (cursor < end) { curType = CharType.Get(chars[cursor]); // 获取符号类型 if (curType != CT_NUM) { break; // 类型不一致,退出循环 } cursor++; } } atoms.Add(new AtomNode(new string(chars, start, cursor - start), preType)); // start = cursor; } preType = curType; // 更新当前字符的类型 cursor++; // 更新指针指向下一个字符 } if (cursor == end) // 还有一种可能就是cursor= end + 1,这种情况时最后末尾为一个浮点数,已经加入列表 { atoms.Add(new AtomNode(new string(chars, start, end - start), preType)); } return(atoms); }
/// <summary> /// 原子分词 /// 仅对数字以及单字节字符连接处理为一个AtomNode,其他每个字符自成一个AtomNode /// 考虑了浮点数 /// </summary> /// <param name="chars">待分词字符数组</param> /// <param name="start">起始点 inclusive</param> /// <param name="end">截止点 exclusive</param> /// <returns></returns> protected static List <AtomNode> AtomSegment(char[] chars, int start, int end) { var atoms = new List <AtomNode>(); var sb = new StringBuilder(); char c; var charTypeArr = new int[end - start]; // 创建用于保存字符类型的数组 for (int i = 0; i < charTypeArr.Length; i++) { c = chars[i + start]; // 当前字符 charTypeArr[i] = CharType.Get(c); // 当前字符的类型 //! 对几种特殊情况作类型调整 if (c == '.' && i + start < (chars.Length - 1) && CharType.Get(chars[i + start + 1]) == CT_NUM) // 如果当前是 dot,并且后面跟的字符是数字类型,则标记当前位置类型为数字类型 { charTypeArr[i] = CT_NUM; } //else if (c == '.' && i + start < (chars.Length - 1) && chars[i + start + 1] >= '0' && chars[i + start + 1] <= '9') //todo: 这个条件不是跟上面一样吗? // charTypeArr[i] = CT_SINGLE; else if (charTypeArr[i] == CT_LETTER) // 如果为字母类型,则先统一改成 “单字节” 字符类型 { charTypeArr[i] = CT_SINGLE; } } int cursor = start; int curType, nextType; // 对每个字符以及字符类型,构建一个原子节点对象并添加到列表。只有遇到连续数字类型时,将连续的表示数字(integer or float)的字符串作为一个整体原子节点 while (cursor < end) { curType = charTypeArr[cursor - start]; // 当前字符类型 if (curType == CT_CHINESE || curType == CT_INDEX || curType == CT_DELIMITER || curType == CT_OTHER) { atoms.Add(new AtomNode(chars[cursor], curType)); cursor++; } //! 遇到连续的单字节字符,或者连续的“数字” 类型的字符,则将这些连续的相同类型字符的字符串作为一个整体,构建原子节点对象 else if (cursor < end - 1 && (curType == CT_SINGLE || curType == CT_NUM)) { sb.Clear(); sb.Append(chars[cursor]); // 将当前数字/单字节 字符添加到缓冲区 bool used = true; // 当前指针指向的字符是否被使用 while (cursor < end - 1) // 尚未达到最后一个字符 { nextType = charTypeArr[++cursor - start]; // 下一个字符类型,并将指针指向下一个字符 if (nextType == curType) { sb.Append(chars[cursor]); } else { used = false; break; } } atoms.Add(new AtomNode(sb.ToString(), curType)); if (used) // 如果当前指针指向字符 已经被使用,cursor 需要 增 1 { cursor++; // } } else { atoms.Add(new AtomNode(chars[cursor], curType)); cursor++; } } return(atoms); }