code: def _concat_clip(data_bundle, max_len, concat_field_name="raw_chars"):
      r"""
      处理data_bundle中的DataSet，将context与question按照character进行tokenize，然后使用[SEP]将两者连接起来。
  
      会新增field: context_len(int), raw_words(list[str]), target_start(int), target_end(int)其中target_start
      与target_end是与raw_chars等长的。其中target_start和target_end是前闭后闭的区间。
  
      :param DataBundle data_bundle: 类似["a", "b", "[SEP]", "c", ]
      :return:
      """
      tokenizer = get_tokenizer("cn-char", lang="cn")
      for name in list(data_bundle.datasets.keys()):
          ds = data_bundle.get_dataset(name)
          data_bundle.delete_dataset(name)
          new_ds = DataSet()
          for ins in ds:
              new_ins = deepcopy(ins)
              context = ins["context"]
              question = ins["question"]
  
              cnt_lst = tokenizer(context)
              q_lst = tokenizer(question)
  
              answer_start = -1
  
              if (
                  len(cnt_lst) + len(q_lst) + 3 > max_len
              ):  # 预留开头的[CLS]和[SEP]和中间的[sep]
                  if "answer_starts" in ins and "answers" in ins:
                      answer_start = int(ins["answer_starts"][0])
                      answer = ins["answers"][0]
                      answer_end = answer_start + len(answer)
                      if answer_end > max_len - 3 - len(q_lst):
                          span_start = (
                              answer_end + 3 + len(q_lst) - max_len
                          )
                          span_end = answer_end
                      else:
                          span_start = 0
                          span_end = max_len - 3 - len(q_lst)
                      cnt_lst = cnt_lst[span_start:span_end]
                      answer_start = int(ins["answer_starts"][0])
                      answer_start -= span_start
                      answer_end = answer_start + len(ins["answers"][0])
                  else:
                      cnt_lst = cnt_lst[: max_len - len(q_lst) - 3]
              else:
                  if "answer_starts" in ins and "answers" in ins:
                      answer_start = int(ins["answer_starts"][0])
                      answer_end = answer_start + len(ins["answers"][0])
  
              tokens = cnt_lst + ["[SEP]"] + q_lst
              new_ins["context_len"] = len(cnt_lst)
              new_ins[concat_field_name] = tokens
  
              if answer_start != -1:
                  new_ins["target_start"] = answer_start
                  new_ins["target_end"] = answer_end - 1
  
              new_ds.append(new_ins)
          data_bundle.set_dataset(new_ds, name)
  
      return data_bundle
  
file_path: fastNLP/fastNLP/io/pipe/qa.py
imports: from copy import deepcopy
  from .pipe import Pipe
  from fastNLP.io.data_bundle import DataBundle
  from ..loader.qa import CMRC2018Loader
  from .utils import get_tokenizer
  from fastNLP.core.dataset import DataSet
  from fastNLP.core.vocabulary import Vocabulary
label_desc: Use image node_id 1 for calling a global function with example usage: _concat_clip(data_bundle, max_len, concat_field_name) and returns: data_bundle