·
日常编程 ·
92249
本文介绍在逐行处理文本时,使用 spaCy Matcher 提取匹配实例、当前句子及前一句的完整实现方案,核心在于维护跨句子的上下文状态(如 prev_sent 变量),避免因句子无索引而无法回溯的问题。
本文介绍在逐行处理文本时,使用 spacy matcher 提取匹配实例、当前句子及前一句的完整实现方案,核心在于维护跨句子的上下文状态(如 `prev_sent` 变量),避免因句子无索引而无法回溯的问题。
在使用 spaCy 的 Matcher 进行规则匹配时,若需同时获取「匹配片段」「所在完整句子」和「前一句」,关键难点在于:spaCy 的 doc.sents 是生成器,句子对象本身不携带位置索引,也无法直接通过 sent[-1] 获取上一句(该写法实际访问的是句子内最后一个 token)。正确解法是在遍历句子时主动维护一个指向“上一句”的引用变量,并在每次匹配成功时读取该引用。
以下为优化后的完整实现流程:
-
matcher 初始化一次,复用提升性能:将 Matcher 实例创建移至文件循环外,避免重复构建;
-
逐句遍历 + 状态追踪:对每个 doc 调用 doc.sents,用 prev_sent 缓存上一个句子对象;
-
安全访问前一句:仅当 prev_sent is not None 时取 prev_sent.text,否则填充 "N/A" 或空字符串;
-
精准匹配范围:matcher(sent) 直接作用于句子级 Span,确保匹配逻辑与语境一致(而非整行文档)。
import spacy
from spacy.matcher import Matcher
import pandas as pd
nlp = spacy.load("en_core_web_sm")
pattern = [{"LOWER": "error"}, {"POS": "VERB"}] # 示例:匹配 "error occurred" 类模式
matcher = Matcher(nlp.vocab)
matcher.add("ERROR_PATTERN", [pattern])
instances = []
with open('file.txt', 'r') as f:
for line in iter(f.readline, ''):
doc = nlp(line.strip()) # 去除换行符,避免空句干扰
prev_sent = None
for sent in doc.sents:
matches = matcher(sent)
if matches:
for match_id, start, end in matches:
matched_span = sent[start:end]
instances.append(pd.Series({
"instance": matched_span.text,
"sentence": sent.text.strip(),
"previous_sentence": prev_sent.text.strip() if prev_sent else "N/A"
}))
prev_sent = sent # 更新为当前句,供下一轮使用
df = pd.DataFrame(instances)
print(df[["instance", "sentence", "previous_sentence"]])
⚠️ 注意事项:
-
单行即单文档假设:本方案默认每行是独立语义单元(如日志条目、对话轮次)。若需跨行连贯句子分割(如段落级断句),应先合并多行为完整文本再调用 nlp(),并改用 doc[i-1:i] 等索引方式定位前句;
-
空句/标点边界问题:doc.sents 依赖模型内置断句规则,对简短或格式异常的行(如纯数字、无标点)可能失效,建议预处理或添加 if len(list(sent)) > 0: 校验;
-
性能考量:若文件极大,可考虑使用 nlp.pipe() 批量处理,但需注意 sents 迭代逻辑需适配批处理结构。
该方法简洁、鲁棒且符合 spaCy 最佳实践,适用于日志分析、合规审查、问答上下文提取等需局部语境感知的 NLP 场景。
grpcio-reflection 无异步支持因其 servicer 继承同步基类、无 AsyncServicer 实现且依赖同步 I/O;异步调用反射需用 grpc.aio.Channel + stub.ServerReflectionInfo 并 await,自研异步服务端须重写方法并缓存 FileDescriptorSet。 Python 的 grpcio 官方库从 1.39 版本起才正式支...
在 discord.py 中,用户添加 ❤️ 表情时 emo.emoji 实际返回的是带变体选择符的 Unicode 序列(如 '❤️'),而非基础字符 '❤',直接用 == '❤' 比较会失败;需统一使用带变体的选择符版本或标准化处理。 在 discord.py 中,用户添加 ❤️ 表情时 `emo.emoji` 实际返回的是带变体选择符的 unicode 序列(如 `'❤️'`),而非基础字符...
在 LlamaIndex 中调用 aevaluate_queries() 等异步方法时,必须将 await 语句置于 async 函数内部,并通过 asyncio.run() 启动事件循环;直接在模块顶层 await 会导致 SyntaxError,这是 Python 异步语法的硬性限制。 在 llamaindex 中调用 `aevaluate_queries()` 等异步方法时,必须将 `awa...
os.listdir()返回指定路径下一级子项(文件和文件夹)的名称列表,故len()统计的是条目总数而非纯文件数;需配合os.path.isfile(os.path.join(path, f))过滤才能准确计数。 os.listdir() 返回的是什么,为什么不能直接用 len() 统计子目录里的文件数 os.listdir() 只返回指定路径下**一级子项的名称列表**(包括文件和文件夹),不...
asyncio.all_tasks 返回当前事件循环中所有未完成的Task对象集合(set),为空常因未启动事件循环、无活跃循环、任务已完结或跨线程未正确设置循环。 asyncio.all_tasks 返回什么,为什么有时为空 asyncio.all_tasks 返回当前事件循环中所有未完成的 Task 对象集合(set),但它**只作用于当前线程中已运行且未关闭的事件循环**。常见误区是直接调用...
Faiss将向量搜索从O(N)降至近O(log N),通过索引、量化与压缩实现加速;选错索引类型会导致构建失败或结果不准,小规模用IndexFlatL2,中大规模依数据量选IVF或HNSW。 为什么直接用 NumPy 算余弦相似度会变慢 当向量数量超过 10 万,用 sklearn.metrics.pairwise.cosine_similarity 或手写 np.dot + 归一化做全量比对,内...
Aggregate返回单条字典结果,annotate为每条记录添加字段并保持QuerySet可链式操作;分组聚合必须用values()配合annotate,Aggregate不能用于已分组查询。 直接用 Aggregate 做复杂统计报表,大概率会卡在“查不出想要的分组结构”或“多层聚合嵌套报错”上——它本身不处理分组,只做单次聚合计算,真要出报表,得和 values()、annotate() 配...
subprocess.check_output 默认吞掉 stderr 且不暴露,仅当退出码非零才抛异常;需改用 subprocess.run(..., capture_output=True, check=True) 分别获取 stdout 和 stderr。 subprocess.check_output 会吞掉 stderr 吗 会,而且默认情况下完全不暴露 stderr。调用 subpro...
本文详解 discord.py 中因 Unicode 变体选择器(VS16)导致的 ❤️ 表情符号匹配失败问题,揭示 ❤ 与 ❤️ 的本质区别,并提供可靠、可复用的解决方案。 本文详解 discord.py 中因 unicode 变体选择器(vs16)导致的 ❤️ 表情符号匹配失败问题,揭示 `❤` 与 `❤️` 的本质区别,并提供可靠、可复用的解决方案。 在 Discord 中,用户点击的“❤”...
本文详解在 pyvespa 中部署 onnx 模型时常见的路径引用错误,重点说明为何不能在应用包中直接引用宿主机或 docker 卷中的 onnx 文件,并提供可落地的解决方案:将模型文件嵌入 zip 包、正确配置 schema 与 model 定义、确保资源分配充足。 本文详解在 pyvespa 中部署 onnx 模型时常见的路径引用错误,重点说明为何不能在应用包中直接引用宿主机或 docker...