从散文中拆分句子:保留对话标记与标点的技术难题
解决散文句子拆分并保留对话标记的问题
我来帮你搞定这个句子拆分的问题!针对你提到的两个核心痛点——区分Mr.这类缩写的句点和句末标点、正确保留对话引号,我整理了一套可行的实操方案:
一、先搞定缩写句点的误判问题
首先,我们得给常见的英文缩写建个「白名单」,比如Mr.、Mrs.、Dr.、St.这些,避免拆分时把它们的句点当成句子结束的标志。具体步骤是:
- 先遍历文本,把缩写里的句点替换成一个临时占位符(比如
__DOT__),这样后续拆分句子时就不会认错。 - 等句子拆分完成后,再把占位符还原回正常的句点。
二、正确处理对话引号的拆分逻辑
对话的引号必须和对应的句子绑定,不能拆分家。这里的关键是先把对话和非对话内容分开处理:
- 分割对话与非对话:通过匹配成对的引号(
“和”)把文本拆成对话片段和非对话片段。 - 拆分对话内部的句子:在对话片段里,以
!、?、.(已经处理过缩写的句点)作为句子结束的标志拆分。 - 给对话句子补全引号:每个拆分后的对话句子,都要加上首尾的引号,保证格式完整。
- 非对话部分正常拆分:直接按句末标点拆分就行,不用管引号。
三、示例实现(伪代码)
下面是用Python写的核心逻辑,你可以直接参考调整:
# 第一步:定义缩写白名单 abbreviation_list = {"Mr.", "Mrs.", "Dr.", "St.", "Jr.", "Sr."} def mark_abbreviations(text): # 把缩写里的句点换成占位符 for abbr in abbreviation_list: text = text.replace(abbr, abbr.replace(".", "__DOT__")) return text def restore_abbreviations(text): # 把占位符还原回句点 return text.replace("__DOT__", ".") def split_dialogue_sections(text): # 拆分对话和非对话片段 sections = [] current_index = 0 while True: # 找对话起始引号 start_quote = text.find("“", current_index) if start_quote == -1: # 剩下的都是非对话内容 if current_index < len(text): sections.append(("non_dialogue", text[current_index:].strip())) break # 提取引号前的非对话内容 if start_quote > current_index: sections.append(("non_dialogue", text[current_index:start_quote].strip())) # 找对话结束引号 end_quote = text.find("”", start_quote + 1) if end_quote == -1: # 处理不完整的引号(可选逻辑) sections.append(("dialogue", text[start_quote:].strip())) break # 提取对话内容(去掉首尾引号) dialogue_content = text[start_quote+1:end_quote].strip() sections.append(("dialogue", dialogue_content)) current_index = end_quote + 1 return sections def split_into_sentences(text): # 按句末标点拆分句子 sentence_endings = {"!", "?", "."} sentences = [] current_sentence = "" for char in text: current_sentence += char if char in sentence_endings: sentences.append(current_sentence.strip()) current_sentence = "" # 处理最后一段没写完的句子 if current_sentence.strip(): sentences.append(current_sentence.strip()) return sentences def split_text_with_dialogue(text): # 主函数:整合所有逻辑 # 1. 标记缩写 processed_text = mark_abbreviations(text) # 2. 拆分对话和非对话 sections = split_dialogue_sections(processed_text) final_result = [] for section_type, content in sections: if section_type == "dialogue": # 拆分对话句子,补全引号 dialogue_sentences = split_into_sentences(content) for sent in dialogue_sentences: restored_sent = restore_abbreviations(sent) final_result.append(f“{restored_sent}”) else: # 拆分非对话句子 non_dialogue_sentences = split_into_sentences(content) for sent in non_dialogue_sentences: restored_sent = restore_abbreviations(sent) final_result.append(restored_sent) return final_result # 测试你的示例文本 test_input = "“Dirty, Mr. Jones? Look at my shoes! Not a speck on them.” This is a non-dialogue sentence!" print(split_text_with_dialogue(test_input)) # 输出:["“Dirty, Mr. Jones?”", "“Look at my shoes!”", "“Not a speck on them.”", "This is a non-dialogue sentence!"]
四、一些额外提示
- 缩写白名单可以根据你的需求扩展,比如加入行业专属的缩写(像
Prof.、Cmdr.这类)。 - 如果你的文本用的是英文引号(
"),只需要把代码里的“和”换成"就行。 - 要是遇到嵌套对话(比如对话里又引用了别人的话),可能需要加递归处理逻辑,但基础场景下上面的代码已经完全够用了。
内容的提问来源于stack exchange,提问作者Kevin Connors
相关产品推荐
相关产品推荐

