赞
踩
传统的文本分割方法在处理长句子时可能会产生意外的结果,因为它在分割句子时并没有考虑语义,只是基于标点符号和字符数量进行的。
from langchain.text_splitter import CharacterTextSplitter import re from typing import List from configs.model_config import SENTENCE_SIZE class ChineseTextSplitter(CharacterTextSplitter): def __init__(self, pdf: bool = False, sentence_size: int = SENTENCE_SIZE, **kwargs): super().__init__(**kwargs) self.pdf = pdf self.sentence_size = sentence_size def split_text1(self, text: str) -> List[str]: if self.pdf: text = re.sub(r"\n{3,}", "\n", text) text = re.sub('\s', ' ', text) text = text.replace("\n\n", "") sent_sep_pattern = re.compile('([﹒﹔﹖﹗.。!?]["’”」』]{0,2}|(?=["‘“「『]{1,2}|$))') # del :; sent_list = [] for ele in sent_sep_pattern.split(text): if sent_sep_pattern.match(ele) and sent_list: sent_list[-1] += ele elif ele: sent_list.append(ele) return sent_list def split_text(self, text: str) -> List[str]: ##此处需要进一步优化逻辑 if self.pdf: text = re.sub(r"\n{3,}", r"\n", text) text = re.sub('\s', " ", text) text = re.sub("\n\n", "", text) text = re.sub(r'([;;.!?。!?\?])([^”’])', r"\1\n\2", text) # 单字符断句符 text = re.sub(r'(\.{6})([^"’”」』])', r"\1\n\2", text) # 英文省略号 text = re.sub(r'(\…{2})([^"’”」』])', r"\1\n\2", text) # 中文省略号 text = re.sub(r'([;;!?。!?\?]["’”」』]{0,2})([^;;!?,。!?\?])', r'\1\n\2', text) # 如果双引号前有终止符,那么双引号才是句子的终点,把分句符\n放到双引号后,注意前面的几句都小心保留了双引号 text = text.rstrip() # 段尾如果有多余的\n就去掉它 # 很多规则中会考虑分号;,但是这里我把它忽略不计,破折号、英文双引号等同样忽略,需要的再做些简单调整即可。 ls = [i for i in text.split("\n") if i] for ele in ls: if len(ele) > self.sentence_size: ele1 = re.sub(r'([,,.]["’”」』]{0,2})([^,,.])', r'\1\n\2', ele) ele1_ls = ele1.split("\n") for ele_ele1 in ele1_ls: if len(ele_ele1) > self.sentence_size: ele_ele2 = re.sub(r'([\n]{1,}| {2,}["’”」』]{0,2})([^\s])', r'\1\n\2', ele_ele1) ele2_ls = ele_ele2.split("\n") for ele_ele2 in ele2_ls: if len(ele_ele2) > self.sentence_size: ele_ele3 = re.sub('( ["’”」』]{0,2})([^ ])', r'\1\n\2', ele_ele2) ele2_id = ele2_ls.index(ele_ele2) ele2_ls = ele2_ls[:ele2_id] + [i for i in ele_ele3.split("\n") if i] + ele2_ls[ ele2_id + 1:] ele_id = ele1_ls.index(ele_ele1) ele1_ls = ele1_ls[:ele_id] + [i for i in ele2_ls if i] + ele1_ls[ele_id + 1:] id = ls.index(ele) ls = ls[:id] + [i for i in ele1_ls if i] + ls[id + 1:] return ls
这段代码主要是定义了一个名为ChineseTextSplitter的类,该类继承自CharacterTextSplitter,目的是对中文文本进行分句处理。这个类的两个主要方法是split_text1和split_text,分别实现了两种不同的分句逻辑。
init 方法:这是类的初始化方法,其中pdf用于指示输入的文本是否来自PDF文档;sentence_size是划分句子时句子的最大长度。
split_text1 方法:这个方法首先根据是否是PDF进行预处理,包括去除连续的换行符和空白字符,然后用正则表达式来定义句子的分隔符,将文本分割成一系列的句子,并返回这些句子的列表。
split_text 方法:这个方法首先对PDF文档进行预处理,然后使用一系列的正则表达式进行句子分割。如果句子的长度超过了sentence_size,它会尝试使用更小的单位进行分割,包括逗号、换行符、空格等。
此代码的主要用途应该是用于处理中文文本,尤其是来自PDF文档的文本,以便后续的NLP任务(例如情感分析、文本分类、文本生成等)可以处理更小、更容易管理的句子,而不是整个文档。
请注意,这段代码在处理长句子时可能会产生意外的结果,因为它在分割句子时并没有考虑语义,只是基于标点符号和字符数量进行的。因此,在使用这个类时,可能需要对结果进行后处理,以确保分割的句子在语义上是完整的。
后处理句子的语义完整性通常涉及使用一些自然语言理解(Natural Language Understanding, NLU)的技术。这些技术可以帮助我们理解句子的结构和含义,从而在断句时能保证每个分割的部分都是有意义的。这是一个相对复杂的过程,具体的方法可能会根据应用的需求和所使用的语言的特点而变化。
一种可能的方法是使用句法分析(Syntactic Analysis)或者句法解析(Parsing)。这种技术可以帮助我们理解句子的结构,识别出句子中的名词、动词、形容词等部分,以及他们之间的关系。例如,我们可以使用句法分析来确保每个分割的部分都包含了一个完整的“动词短语”或者“名词短语”,这样可以确保分割的部分在语义上是完整的。
另一种方法是使用语义角色标注(Semantic Role Labeling, SRL)。这种技术可以帮助我们理解句子的含义,识别出句子中的主语、宾语、动词等部分,以及他们之间的关系。例如,我们可以使用SRL来确保每个分割的部分都包含了一个完整的“事件”或“行为”,这样可以确保分割的部分在语义上是有意义的。
此外,我们还可以使用深度学习的方法,例如序列到序列(seq2seq)模型、Transformer模型等,训练一个模型来预测句子分割的位置。这种方法的优点是可以从大量的数据中自动学习句子的结构和含义,无需手动定义规则。但是,这种方法需要大量的标注数据和计算资源。
最后,请注意这些技术都无法保证100%的准确性。在实际使用中,我们可能需要结合多种方法,并使用人工检查来确保结果的质量。
句法分析,也称为句法解析或解析,是自然语言处理(NLP)中的一种技术。它的主要任务是根据一组语法规则分析一句话或一段话,从而确定这些话语的句法结构。
在自然语言中,句法结构通常可以表示为一种树状结构,称为句法树或解析树。在这个树中,每个单词都是一个叶节点,而每个内部节点都表示一种句法关系。根节点通常表示整个句子。
例如,考虑英语句子 “The cat sat on the mat.”。它的句法树可能如下所示:
[Sentence [Noun Phrase [Determiner "The"] [Noun "cat"] ] [Verb Phrase [Verb "sat"] [Prepositional Phrase [Preposition "on"] [Noun Phrase [Determiner "the"] [Noun "mat"] ] ] ] ]
这个树表示了句子中各个单词之间的句法关系。例如,“cat”是名词短语的核心,而“on the mat”是前置词短语,用来修饰动词"sat"。
句法分析的方法通常可以分为两类:规则驱动的方法和统计驱动的方法。规则驱动的方法主要基于预先定义的语法规则来进行解析,如上述的句法树;而统计驱动的方法则主要基于机器学习算法,尤其是深度学习算法。
句法分析在NLP中有许多应用,包括但不限于:信息提取、问答系统、机器翻译、情感分析等。
你可以使用Python中的自然语言处理库,如spaCy、NLTK(Natural Language Toolkit)等来进行句法分析。这些库通常会提供一些预训练模型,可以直接用于句法解析。以下是一个使用spaCy进行句法解析的简单示例:
import spacy
# 加载英文模型
nlp = spacy.load('en_core_web_sm')
# 解析一个句子
doc = nlp('The cat sat on the mat.')
# 打印每个词的依赖关系
for token in doc:
print(token.text, token.dep_, token.head.text)
在这个例子中,我们首先加载了一个预训练的英文模型。然后,我们使用这个模型来解析一个句子。最后,我们打印了每个词的文本、依赖关系和头部词。
这只是最基础的使用方法。句法解析是一个复杂的任务,有很多细节需要处理。你可能需要阅读更多的文档,或者查阅相关的学术论文,以获取更深入的理解和更高级的使用方法。
除此之外,如果你想要处理中文句子,可以使用斯坦福大学开发的Stanford CoreNLP工具,它支持多种语言,包括中文。
注意:进行句法解析需要一定的计算资源,如果处理的文本量很大,可能需要使用一些优化技巧,或者使用更强大的硬件。
也请注意,句法解析通常只能提供语法结构的信息,而不能提供深层次的语义信息。如果你需要理解句子的深层含义,可能需要使用一些更复杂的技术,如语义角色标注(Semantic Role Labeling)或者知识图谱(Knowledge Graph)。
在最初的这个例子中,我们首先假设spaCy库可以支持中文句法解析。具体的代码可能看起来像这样:
import spacy from typing import List import re class SentenceSplitter: def __init__(self): self.nlp = spacy.load('zh_core_web_sm') # 假设zh_core_web_sm是spaCy中可用的中文模型 def is_valid_sentence(self, sentence: str) -> bool: # 这是一个基础的示例,你可能需要更复杂的逻辑来判断一个句子是否在语义上是完整的 doc = self.nlp(sentence) # 检查句子是否有根(root)依赖关系,如果有,我们可以认为它在语义上是完整的 return any(token.dep_ == 'ROOT' for token in doc) def split_text(self, text: str) -> List[str]: # 使用原始的分割逻辑 raw_sentences = re.split(r'([.!?。!?\?]["’”」』]{0,2})', text) sentences = [] buffer = '' for raw_sentence in raw_sentences: buffer += raw_sentence if self.is_valid_sentence(buffer): sentences.append(buffer) buffer = '' if buffer: sentences.append(buffer) # 把最后一段不完整的句子也加进来 return sentences splitter = SentenceSplitter() text = '这是一个例子。这是一个非常复杂的,需要多种方法来处理的例子。' print(splitter.split_text(text))
这个示例代码首先使用和原始函数类似的正则表达式来初步分割文本。然后,对于每个初步分割出的句子,它会检查句子是否在语义上是完整的。如果是,它就把句子加入到结果列表中。如果不是,它就把句子加入到一个缓冲区中,等待和下一段文本一起处理。这样,如果一个句子被错误地分割到了两段中,我们就可以把它们合并回来。
请注意这个例子只是一个简化的示例,实际的逻辑可能需要更复杂。特别是,is_valid_sentence函数目前只是检查句子是否有根(root)依赖关系,这可能不足以判断一个句子是否在语义上是完整的。你可能需要编写更复杂的逻辑来处理这个问题。
同时需要注意,截至2021年,spaCy并未官方支持中文模型,上述示例中使用的zh_core_web_sm只是一个假设的模型名称。要解析中文句法,可能需要借助StanfordNLP或其他能够支持中文的自然语言处理库。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。