news 2026/8/9 11:39:47

构建Python文本安全处理管道:从正则表达式到Aho-Corasick算法实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
构建Python文本安全处理管道:从正则表达式到Aho-Corasick算法实战

在技术开发与内容创作领域,我们时常会遇到一些看似与主流技术无关,但实则能引发对数据清洗、内容安全、命名规范等核心工程问题深度思考的案例。本文将以一个高度抽象化的技术视角,探讨如何从一段非常规的输入文本中,提炼出对开发者具有普遍价值的工程实践与安全启示。我们将围绕文本解析、内容安全过滤、正则表达式应用、以及工程化命名规范等主题,构建一套可复用的技术解决方案。

本文适合所有涉及用户输入处理、内容审核、数据清洗场景的后端开发者、全栈工程师以及安全工程师阅读。通过本文,你将掌握如何系统性地设计一个健壮的内容预处理管道,理解安全底线在代码中的具体体现,并学会编写可维护、可扩展的文本处理工具。

1. 背景与核心概念:非常规输入引发的工程思考

在真实的软件系统中,用户输入是不可预测的。输入可能包含:

  1. 有效业务数据:如用户名、搜索关键词、评论内容。
  2. 无意噪声:如额外的空格、换行符、乱码。
  3. 恶意或违规内容:如脚本注入、敏感词、违反公序良俗的文本。
  4. 测试或探索性输入:用户或测试人员输入的边界案例或无意义字符串。

本文标题所展示的文本,属于上述第3类和第4类的混合体。从技术角度看,它不是一个有效的业务数据,而是一个需要被系统识别、过滤或安全处理的“异常输入”。处理这类输入的核心目标不是理解其语义,而是防止其破坏系统逻辑、污染数据存储、触发安全风险或影响其他用户。

为什么开发者需要掌握这套处理方法?

  • 数据质量:确保存入数据库的文本是干净、合规的。
  • 系统安全:防止XSS(跨站脚本攻击)、注入攻击等。
  • 内容安全:遵守法律法规与平台内容政策,构建健康生态。
  • 系统健壮性:优雅处理各类边界输入,避免程序崩溃或产生不可预期的行为。
  • 可维护性:建立统一的处理标准和工具函数,便于团队协作和后续迭代。

2. 环境准备与版本说明

我们将使用Python 3.8+作为演示语言,因其在文本处理和快速原型开发方面具有优势。以下工具和库将贯穿全文:

  • 操作系统:Windows 10/11, macOS, 或 Linux (如 Ubuntu 20.04+)。
  • Python 环境:建议使用venvconda创建虚拟环境。
  • 核心库
    • re(Python内置):用于正则表达式匹配和替换。
    • html(Python内置):用于HTML实体转义。
  • 可选库(用于更复杂的场景):
    • jieba:中文分词库,用于基于词库的敏感词过滤。
    • ahocorasick:多模式匹配算法库,高效检测大量敏感词。

项目结构预览:

text_safety_pipeline/ ├── utils/ │ ├── __init__.py │ ├── text_cleaner.py # 文本清洗核心模块 │ └── safety_filter.py # 安全过滤模块 ├── config/ │ └── sensitive_words.txt # 敏感词库文件 ├── tests/ │ └── test_cleaner.py # 单元测试 └── main.py # 主程序或示例调用

版本需要根据你的项目实际情况调整,本文示例以常见环境为例,重点演示配置思路和代码逻辑。

3. 核心语法、配置与原理拆解

3.1 正则表达式(Regex)基础与应用

正则表达式是文本处理的瑞士军刀。我们将用它来识别和移除不需要的字符或模式。

常见操作:

  1. 匹配(Match):判断文本是否包含特定模式。
  2. 查找(Search):在文本中搜索特定模式。
  3. 替换(Substitute):将匹配到的模式替换为指定内容。
  4. 分割(Split):根据模式分割文本。

关键元字符:

  • .:匹配任意单个字符(除换行符)。
  • \d:匹配数字。
  • \w:匹配字母、数字、下划线。
  • \s:匹配空白字符(空格、制表符、换行符)。
  • []:字符集,匹配其中任意一个字符。
  • [^]:否定字符集,匹配不在其中的任意字符。
  • *:匹配前一个字符0次或多次。
  • +:匹配前一个字符1次或多次。
  • ?:匹配前一个字符0次或1次。
  • {m,n}:匹配前一个字符m到n次。
  • ^:匹配字符串开头。
  • $:匹配字符串结尾。
  • |:或操作。

3.2 文本清洗的层次化策略

处理输入文本应遵循“分层防御”策略,从简单到复杂,从通用到具体:

  1. 修剪(Trim):移除首尾空白符。
  2. 标准化(Normalize):统一字符编码(如UTF-8)、全半角转换、大小写转换。
  3. 无效字符过滤(Invalid Character Filtering):移除或替换系统不允许的字符(如控制字符、特定符号)。
  4. 模式过滤(Pattern Filtering):使用正则表达式移除或替换特定模式(如连续标点、乱码组合)。
  5. 敏感词过滤(Sensitive Word Filtering):基于词库进行内容安全过滤。
  6. 转义(Escape):对即将插入HTML或SQL的文本进行转义,防止注入攻击。

3.3 安全过滤的原理

敏感词过滤通常采用以下算法之一:

  • 遍历匹配:最简单,但效率低,适用于词库很小的情况。
  • Trie树(字典树):将敏感词库构建成树形结构,实现高效的多模式匹配。
  • Aho-Corasick算法:在Trie树基础上增加了失败指针,能在一次扫描中匹配所有模式串,是工业级敏感词过滤的常用选择。

4. 完整实战案例:构建文本安全处理管道

我们将一步步构建一个名为TextSafetyPipeline的处理器。

4.1 创建项目结构与基础工具类

首先,创建工具类TextCleaner,负责基础的清洗工作。

# utils/text_cleaner.py import re import html class TextCleaner: """ 文本清洗工具类,负责基础清洗和标准化。 """ @staticmethod def trim(text): """移除首尾空白字符""" return text.strip() @staticmethod def remove_extra_spaces(text): """将连续的多个空格替换为单个空格""" return re.sub(r'\s+', ' ', text) @staticmethod def remove_control_characters(text): """移除控制字符(ASCII码0-31,127),但保留换行符和制表符""" # 保留 \n (换行), \t (制表符),移除其他控制字符 return re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', text) @staticmethod def normalize_punctuation(text): """将全角标点转换为半角标点(示例)""" # 这是一个简单的映射示例,实际可能需要更全面的映射表 full_to_half = { ',': ',', '。': '.', '!': '!', '?': '?', ';': ';', ':': ':', '“': '"', '”': '"', '‘': "'", '’': "'", '(': '(', ')': ')', '【': '[', '】': ']', '《': '<', '》': '>', } for full, half in full_to_half.items(): text = text.replace(full, half) return text @staticmethod def filter_by_pattern(text, pattern, replacement=''): """ 使用正则表达式模式过滤文本 :param text: 原始文本 :param pattern: 正则表达式模式字符串 :param replacement: 替换内容,默认为空字符串(即移除) :return: 过滤后的文本 """ try: compiled_pattern = re.compile(pattern) return compiled_pattern.sub(replacement, text) except re.error as e: # 记录日志,并返回原始文本,避免因错误正则导致服务不可用 print(f"正则表达式编译错误: {e}, 模式: {pattern}") return text @staticmethod def html_escape(text): """对文本中的HTML特殊字符进行转义,防止XSS""" return html.escape(text) @classmethod def basic_clean(cls, text): """执行基础清洗流水线""" if not isinstance(text, str): return '' text = cls.trim(text) text = cls.remove_control_characters(text) text = cls.normalize_punctuation(text) text = cls.remove_extra_spaces(text) return text

4.2 实现敏感词过滤模块

接下来,实现一个基于Trie树的敏感词过滤器。为了演示,我们先实现一个简单版本,然后介绍使用ahocorasick库的高效版本。

方案A:纯Python实现的简单Trie树过滤器

# utils/safety_filter.py (简单Trie实现) class SimpleTrieFilter: """简单的敏感词过滤器(Trie树实现)""" def __init__(self): self.root = {} self.end_of_word = '#' def add_word(self, word): """向Trie树中添加一个敏感词""" node = self.root for char in word: node = node.setdefault(char, {}) node[self.end_of_word] = self.end_of_word def add_words_from_file(self, filepath): """从文件加载敏感词,每行一个词""" try: with open(filepath, 'r', encoding='utf-8') as f: for line in f: word = line.strip() if word: # 忽略空行 self.add_word(word) except FileNotFoundError: print(f"敏感词文件未找到: {filepath}") def contains_sensitive_word(self, text): """检查文本是否包含敏感词""" for i in range(len(text)): node = self.root for j in range(i, len(text)): if text[j] not in node: break node = node[text[j]] if self.end_of_word in node: return True return False def filter(self, text, replace_char='*'): """过滤文本中的敏感词,并用指定字符替换""" chars = list(text) for i in range(len(text)): node = self.root for j in range(i, len(text)): if text[j] not in node: break node = node[text[j]] if self.end_of_word in node: # 将敏感词部分替换为 replace_char for k in range(i, j + 1): chars[k] = replace_char break # 匹配到一个词后,跳出内层循环 return ''.join(chars)

方案B:使用ahocorasick库的高性能过滤器(推荐用于生产)

首先安装库:pip install pyahocorasick

# utils/safety_filter.py (Aho-Corasick实现) import ahocorasick class AhoCorasickFilter: """基于Aho-Corasick算法的高性能敏感词过滤器""" def __init__(self): self.automaton = ahocorasick.Automaton() def add_word(self, word): """向自动机中添加一个敏感词""" self.automaton.add_word(word, word) def add_words_from_file(self, filepath): """从文件加载敏感词""" try: with open(filepath, 'r', encoding='utf-8') as f: for line in f: word = line.strip() if word: self.add_word(word) self.automaton.make_automaton() # 构建自动机,必须在所有词添加后调用 except FileNotFoundError: print(f"敏感词文件未找到: {filepath}") def filter(self, text, replace_char='*'): """过滤文本,返回过滤后的文本和匹配到的词列表""" matches = list(self.automaton.iter(text)) if not matches: return text, [] # 为了替换,我们需要知道哪些位置被匹配了 # 由于一个字符可能被多个模式匹配,我们记录需要替换的位置 text_chars = list(text) matched_words = [] for end_index, original_word in matches: start_index = end_index - len(original_word) + 1 matched_words.append(original_word) # 将匹配到的词替换为指定字符 for i in range(start_index, end_index + 1): text_chars[i] = replace_char # 去重匹配到的词列表 matched_words = list(set(matched_words)) return ''.join(text_chars), matched_words def contains_sensitive_word(self, text): """快速检查是否包含敏感词""" return any(True for _ in self.automaton.iter(text))

4.3 组装完整的安全处理管道

现在,我们将清洗器和过滤器组合成一个完整的管道。

# utils/text_safety_pipeline.py from .text_cleaner import TextCleaner from .safety_filter import AhoCorasickFilter # 或 SimpleTrieFilter import re class TextSafetyPipeline: """ 文本安全处理管道。 执行顺序:基础清洗 -> 自定义模式过滤 -> 敏感词过滤 -> 安全转义(可选)。 """ def __init__(self, sensitive_word_filepath=None): self.cleaner = TextCleaner() self.filter = AhoCorasickFilter() self.custom_patterns = [ # 示例:过滤掉非中英文、数字、常用标点的字符(可根据业务调整) # r'[^\u4e00-\u9fa5a-zA-Z0-9\s\.,!?;:\'\"\(\)\[\]\-\+=\*&%\$#@`~]', # 注意:上方的正则过于严格,可能误伤合法内容,请谨慎使用。 ] if sensitive_word_filepath: self.filter.add_words_from_file(sensitive_word_filepath) def add_custom_pattern(self, pattern, replacement=''): """添加自定义的正则过滤模式""" self.custom_patterns.append((pattern, replacement)) def process(self, text, do_html_escape=False, replace_char='*'): """ 处理输入文本。 :param text: 原始输入字符串 :param do_html_escape: 是否进行HTML转义(用于Web输出) :param replace_char: 敏感词替换字符 :return: 处理后的安全文本,以及包含的元信息(如是否被过滤) """ if not isinstance(text, str): return '', {'error': 'Input is not a string'} original_text = text # 1. 基础清洗 cleaned_text = self.cleaner.basic_clean(text) # 2. 应用自定义模式过滤 for pattern, replacement in self.custom_patterns: cleaned_text = self.cleaner.filter_by_pattern(cleaned_text, pattern, replacement) # 3. 敏感词过滤 filtered_text, matched_words = self.filter.filter(cleaned_text, replace_char) # 4. 可选HTML转义 final_text = self.cleaner.html_escape(filtered_text) if do_html_escape else filtered_text result_info = { 'original': original_text, 'cleaned': cleaned_text, 'filtered': filtered_text, 'final': final_text, 'sensitive_words_matched': matched_words, 'was_filtered': len(matched_words) > 0 } return final_text, result_info

4.4 编写测试与运行验证

创建主程序或测试脚本来验证我们的管道。

# main.py import os from utils.text_safety_pipeline import TextSafetyPipeline def main(): # 1. 初始化管道,假设敏感词文件在 config/sensitive_words.txt current_dir = os.path.dirname(__file__) word_file = os.path.join(current_dir, 'config', 'sensitive_words.txt') # 确保配置目录和文件存在(示例) os.makedirs(os.path.dirname(word_file), exist_ok=True) # 示例:创建一个简单的敏感词文件(实际项目中应由安全团队维护) with open(word_file, 'w', encoding='utf-8') as f: f.write("违规词A\n不良词B\n测试敏感词\n") pipeline = TextSafetyPipeline(sensitive_word_filepath=word_file) # 2. 添加一些自定义过滤模式(例如过滤掉某些特殊符号组合) # pipeline.add_custom_pattern(r'\[BW胶kig\]', '[内容已过滤]') # 示例:过滤特定标签 # pipeline.add_custom_pattern(r'~+', '~') # 将多个波浪符合并为一个 # 3. 测试用例 test_cases = [ " 这是一段正常的评论,包含数字123和标点。 ", "这个文本包含违规词A,需要被过滤。", "另一个例子,这里有测试敏感词和不良词B。", "[BW胶kig]银狼的胶腿~捏捏~全是水,全是汗~咕噜咕噜~", # 原始输入 "<script>alert('xss')</script>", # XSS尝试 " multiple spaces and\t tabs ", # 多余空白 ] print("=" * 50) print("文本安全处理管道测试") print("=" * 50) for i, test_text in enumerate(test_cases): print(f"\n测试用例 {i+1}:") print(f" 原始输入: {repr(test_text)}") safe_text, info = pipeline.process(test_text, do_html_escape=True) print(f" 最终输出: {repr(safe_text)}") print(f" 是否被过滤: {info['was_filtered']}") if info['sensitive_words_matched']: print(f" 匹配到的敏感词: {info['sensitive_words_matched']}") print(f" 清洗后文本: {repr(info['cleaned'])}") print(f" 敏感词过滤后文本: {repr(info['filtered'])}") if __name__ == "__main__": main()

4.5 运行结果说明

运行python main.py,预期会得到类似以下的输出(具体敏感词匹配结果取决于你的词库文件):

================================================== 文本安全处理管道测试 ================================================== 测试用例 1: 原始输入: ' 这是一段正常的评论,包含数字123和标点。 ' 最终输出: '这是一段正常的评论,包含数字123和标点。' 是否被过滤: False 清洗后文本: '这是一段正常的评论,包含数字123和标点。' 敏感词过滤后文本: '这是一段正常的评论,包含数字123和标点。' 测试用例 2: 原始输入: '这个文本包含违规词A,需要被过滤。' 最终输出: '这个文本包含***,需要被过滤。' 是否被过滤: True 匹配到的敏感词: ['违规词A'] 清洗后文本: '这个文本包含违规词A,需要被过滤。' 敏感词过滤后文本: '这个文本包含***,需要被过滤。' 测试用例 3: 原始输入: '另一个例子,这里有测试敏感词和不良词B。' 最终输出: '另一个例子,这里有****和***。' 是否被过滤: True 匹配到的敏感词: ['测试敏感词', '不良词B'] 清洗后文本: '另一个例子,这里有测试敏感词和不良词B。' 敏感词过滤后文本: '另一个例子,这里有****和***。' 测试用例 4: 原始输入: '[BW胶kig]银狼的胶腿~捏捏~全是水,全是汗~咕噜咕噜~' 最终输出: '[BW胶kig]银狼的胶腿~捏捏~全是水,全是汗~咕噜咕噜~' 是否被过滤: False 清洗后文本: '[BW胶kig]银狼的胶腿~捏捏~全是水,全是汗~咕噜咕噜~' 敏感词过滤后文本: '[BW胶kig]银狼的胶腿~捏捏~全是水,全是汗~咕噜咕噜~' 测试用例 5: 原始输入: "<script>alert('xss')</script>" 最终输出: '&lt;script&gt;alert(&#x27;xss&#x27;)&lt;/script&gt;' 是否被过滤: False 清洗后文本: "<script>alert('xss')</script>" 敏感词过滤后文本: "<script>alert('xss')</script>" 测试用例 6: 原始输入: ' multiple spaces and\t tabs ' 最终输出: 'multiple spaces and tabs' 是否被过滤: False 清洗后文本: 'multiple spaces and tabs' 敏感词过滤后文本: 'multiple spaces and tabs'

结果分析:

  • 用例1、6:展示了基础清洗功能(去首尾空格、合并多余空格)。
  • 用例2、3:展示了敏感词过滤功能,违规词被替换为*
  • 用例4:原始非常规输入,由于未在敏感词库中,且未匹配到自定义过滤模式,因此内容被保留但经过了HTML转义(如果开启)。这引出一个关键点:过滤规则需要精心设计和持续维护。
  • 用例5:展示了HTML转义功能,成功将潜在的XSS攻击脚本转换为无害的文本显示。

5. 常见问题与排查思路

在实现和部署文本安全管道时,你可能会遇到以下问题:

问题现象常见原因解决思路
敏感词过滤漏报1. 敏感词库未更新或未加载。
2. 词库中词形与文本中词形不一致(如简繁体、大小写、全半角)。
3. 过滤算法有Bug(如Trie树未正确构建)。
4. 文本被预处理(如分词)改变了原貌。
1. 检查词库文件路径和加载日志。
2. 对输入文本和词库进行统一的标准化处理(如转为小写、繁体转简体)。
3. 编写单元测试,验证基础词的过滤。
4. 确保过滤在适当的分词或清洗步骤之后进行。
敏感词过滤误报1. 词库包含常见但非敏感的词汇。
2. 算法匹配了子串(如“程序员”中包含“程序”)。
3. 未处理边界情况(如英文单词中的敏感字母组合)。
1. 精细化维护词库,区分绝对敏感词和上下文相关词。
2. 考虑使用更精确的匹配模式(如整词匹配,需结合分词)。
3. 对于英文,可以考虑基于单词边界\b进行匹配。
处理性能低下1. 使用低效算法(如双重循环遍历)。
2. 词库过大,每次处理都重新加载。
3. 正则表达式过于复杂或回溯严重。
1.使用Aho-Corasick等高效多模式匹配算法
2. 将构建好的过滤器对象(如自动机)缓存起来,避免重复构建。
3. 优化正则表达式,避免贪婪匹配和回溯爆炸。
特殊字符或编码问题1. 文本编码非UTF-8。
2. 包含Emoji、生僻字或特殊符号。
3. 正则表达式未正确处理Unicode。
1. 在流程最前端统一转换为UTF-8。
2. 在正则表达式中使用re.UNICODEre.A标志明确处理策略。
3. 谨慎设计字符白名单或黑名单,避免误伤合法字符。
HTML转义影响正常显示1. 对已经转义过的文本进行二次转义。
2. 在不需要转义的场景(如纯文本存储)进行了转义。
1. 明确转义时机:仅在内容输出到HTML页面前进行转义。
2. 存储原始或清洗后的文本,在渲染时动态转义。
规则维护困难1. 过滤规则散落在代码各处。
2. 词库更新需要重启服务。
1.将规则配置化,存储在数据库或配置文件中。
2. 实现规则的热加载机制,如监听配置文件变化或提供管理接口动态更新内存中的词库。

6. 最佳实践与工程建议

将文本安全处理集成到实际项目中时,请遵循以下最佳实践:

  1. 分层设计与责任分离

    • 清洗层:只做与业务无关的标准化和格式化。
    • 过滤层:负责基于规则和词库的内容安全。
    • 转义层:在最后的输出环节,根据上下文(HTML, SQL, JSON)进行编码。
    • 各层之间通过清晰的接口通信,便于单独测试和替换。
  2. 配置化与热更新

    • 绝对不要将敏感词硬编码在代码中。应将其存储在外部文件或数据库中。
    • 设计一个管理后台,允许安全或运营人员动态更新词库和规则,并支持实时或定时同步到应用服务器。
    • 规则文件应使用版本控制。
  3. 性能优化

    • 缓存过滤器对象AhoCorasickFiltermake_automaton()调用成本较高,构建好的自动机应作为单例或缓存对象长期使用。
    • 异步处理:对于批量或耗时较长的文本处理(如审核历史数据),考虑放入消息队列异步处理,避免阻塞主请求。
    • 采样与监控:对处理结果进行采样审计,并监控过滤器的性能指标(如处理时长、内存占用)。
  4. 安全边界与灰度发布

    • 最小权限原则:管理词库的后台需要严格的权限控制。
    • 备份与回滚:更新词库前,备份旧版本。一旦新规则导致大量误报,能快速回滚。
    • 灰度测试:新增加的敏感词或规则,可以先对一小部分流量或特定用户生效,观察效果后再全量。
  5. 日志与审计

    • 记录关键操作:如词库加载成功/失败、规则更新、高频敏感词命中。
    • 记录被过滤的原始文本(需脱敏或加密存储,并严格限制访问权限),用于后续的规则优化和审计追溯。
    • 日志中避免记录完整的敏感词内容,以防泄露。
  6. 处理策略多样化

    • 拒绝:直接驳回包含严重违规内容的请求。
    • 替换:将敏感词替换为*[内容已屏蔽]
    • 审核:将疑似内容标记,转入人工审核队列。
    • 仅自己可见:在社交场景,可将违规内容设置为仅发布者自己可见。
    • 策略的选择应根据违规的严重程度和业务场景灵活配置。
  7. 法律与合规性

    • 内容过滤规则必须符合国家法律法规和平台政策。
    • 对于用户数据的处理,特别是记录和存储,需遵循《个人信息保护法》等相关规定,明确告知用户。
    • 定期审查和更新过滤规则,以应对新的违规形式。

通过构建这样一个系统化、可配置、高性能的文本安全处理管道,开发者能够为应用建立起一道有效的内容安全防线,同时保证系统的健壮性和可维护性。这不仅是处理异常输入的技术方案,更是构建负责任、可持续的在线平台的基础工程能力。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/9 11:38:10

StreamCap:3步解决跨平台直播录制难题的完整方案

StreamCap&#xff1a;3步解决跨平台直播录制难题的完整方案 【免费下载链接】StreamCap Multi-Platform Live Stream Automatic Recording Tool | 多平台直播流自动录制客户端 基于FFmpeg 支持监控/定时/转码 项目地址: https://gitcode.com/gh_mirrors/st/StreamCap …

作者头像 李华
网站建设 2026/8/9 11:34:42

Palworld存档编辑终极指南:用palworld-save-tools解锁游戏无限可能

Palworld存档编辑终极指南&#xff1a;用palworld-save-tools解锁游戏无限可能 【免费下载链接】palworld-save-tools Tools for converting Palworld .sav files to JSON and back 项目地址: https://gitcode.com/gh_mirrors/pa/palworld-save-tools 你是否曾经为Palwo…

作者头像 李华
网站建设 2026/8/9 11:29:32

强亲密 / 强绑定关系沟通:去情绪化、把人格攻击转回事件本身

强亲密 / 强绑定关系沟通:去情绪化、把人格攻击转回事件本身 适用全部强链接场景:领导‑下属、夫妻、父子 / 母子、兄弟姐妹。 核心底层逻辑: 一旦对话出现人身评判、贴标签、人格贬低,沟通已经失效。不要去争辩 “我不是这样的”,不接对方扣过来的人格帽子;先承接情绪强…

作者头像 李华
网站建设 2026/8/9 11:28:07

3步搞定SPT-AKI存档编辑:让《逃离塔科夫》离线模式更自由

3步搞定SPT-AKI存档编辑&#xff1a;让《逃离塔科夫》离线模式更自由 【免费下载链接】SPT-AKI-Profile-Editor Программа для редактирования профиля игрока на сервере SPT-AKI 项目地址: https://gitcode.com/gh_mirror…

作者头像 李华