递归分块的思想是: 先尝试用最大的分隔符切,切完如果某个块还是太大,就换一个更小的分隔符继续切,直到所有块都在 chunkSize 以内。
需注意,此方法最小分隔符需设置为"",也就是单字拆分或者单token拆分,保证能无限细分拆下去,直到<chunkSize
此处使用Java示例表示此分块方式的思路
public class ChunkSpilt {/*** 分隔符列表*/private static final String[] separators = {"\n\n", "\n", ",", ",", "。", " ", ""};/*** chunk最大大小(字符)*/private static final int chunkSize = 50;public static void main(String[] args) {String test = "C++11以前有很多原因不能提供一个通用的split,因为绝大部分人想要的类似于vector<string> split(const string& s, const string& delimiters = \" \") 这种函数是进不了C++标准库的。首先,它返回的是一个vector,而用户想要的可能是list、array,甚至是其它任何用户自定义的容器,这时候就需要自己再拷贝一次。总之就是split返回的结果是一个集合、但是不能限定为任何指定的容器,最好是lazy的,真正需要访问下一个的时候才去split下一个,符合这样的要求的split才能进入C++标准库。";List<String> spilt = spilt(test);System.out.println(spilt.size());for (String s : spilt) {System.out.println(s);}}/*** chunk分割*/private static List<String> spilt(String text) {return spilt(0, text, null);}/*** 递归逐层分割chunk** @param step 当前层数* @param text 原始文本* @param lastSpiltStrings 当前层分割的结果* @return 返回的结果*/private static List<String> spilt(int step, String text, List<String> lastSpiltStrings) {if (step >= separators.length) {// 当前层无法再分割,直接返回return lastSpiltStrings;}String separator = separators[step];if (lastSpiltStrings == null) {lastSpiltStrings = List.of(text.split(separator));} else {// 使用当前层分隔符分割List<String> temp = new ArrayList<>();for (String lastSpiltString : lastSpiltStrings) {temp.addAll(Arrays.asList(lastSpiltString.split(separator)));}lastSpiltStrings = temp;}// 校验每个string是否大于chunkSize,大于则继续拆分,没有了直接返回return lastSpiltStrings.stream().noneMatch(each2 -> each2.length() > chunkSize) ?lastSpiltStrings : spilt(step + 1, text, lastSpiltStrings);}
}
