Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b05a333e07 | ||
|
|
ba1d8a32ff | ||
|
|
dbf0ffc752 | ||
|
|
05c600b439 | ||
|
|
332db8f522 | ||
|
|
a2c61e116b | ||
|
|
f0a167af8f | ||
|
|
80cfc45cb0 | ||
|
|
81a8126d68 | ||
|
|
dbbff0c421 | ||
|
|
dc61c4028a | ||
|
|
f956b85ed3 | ||
|
|
2e8310a3ff | ||
|
|
7e9f75e7c6 | ||
|
|
4e5b60de03 | ||
|
|
f273405baa | ||
|
|
271911af00 | ||
|
|
1fc1425f1f | ||
|
|
c20358708b | ||
|
|
a481141379 | ||
|
|
5d1cb6bc2d | ||
|
|
58c047bb45 | ||
|
|
8b5127f0fc | ||
|
|
851bfae789 | ||
|
|
314888ab40 | ||
|
|
0052d09a63 | ||
|
|
0960121e2d | ||
|
|
a6bdc935a1 | ||
|
|
394f85d9a7 | ||
|
|
7ad6d2b1f2 | ||
|
|
95f3311d2c | ||
|
|
09e3dcbe9a | ||
|
|
ede497398f | ||
|
|
493cc4050f | ||
|
|
4f811bd99e | ||
|
|
01a716b5f3 | ||
|
|
0d79d0e4a5 | ||
|
|
ea25b63f87 | ||
|
|
255134eaf0 | ||
|
|
61498ad26d | ||
|
|
bc85cc190e | ||
|
|
f514baac9e | ||
|
|
ddff71e8e2 | ||
|
|
c0a6a2bf96 | ||
|
|
ddb53a6cfc | ||
|
|
cfd149a42e | ||
|
|
219259f9bb | ||
|
|
8d96e3f03d | ||
|
|
f3333c63e5 | ||
|
|
4b73638afe | ||
|
|
4ade75f525 | ||
|
|
9adedfcd89 | ||
|
|
d9534629a2 | ||
|
|
f515a4de8c | ||
|
|
f3a58a7aa6 |
27
.dockerignore
Normal file
27
.dockerignore
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
.git
|
||||||
|
.github
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
# Build outputs
|
||||||
|
bin/
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
out/
|
||||||
|
|
||||||
|
# Archives & temp
|
||||||
|
*.zip
|
||||||
|
*.tar
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
*.7z
|
||||||
|
*.log
|
||||||
|
*.tmp
|
||||||
|
*.swp
|
||||||
|
~*
|
||||||
|
|
||||||
|
# Optional: exclude non-runtime assets
|
||||||
|
Organized/
|
||||||
|
ThirdPartyCompatibleFormats/
|
||||||
15
.github/FUNDING.yml
vendored
Normal file
15
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||||
|
polar: # Replace with a single Polar username
|
||||||
|
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
|
||||||
|
thanks_dev: # Replace with a single thanks.dev username
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||||
30
.github/workflows/main.yml
vendored
Normal file
30
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
name: 自动测试压缩
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: 拉取代码
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: 设置 Tag 和文件名
|
||||||
|
id: release_info
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||||
|
TAG_NAME="${{ github.event.inputs.tag_name }}"
|
||||||
|
else
|
||||||
|
TAG_NAME="${GITHUB_REF##*/}"
|
||||||
|
fi
|
||||||
|
FILE_NAME="Sensitive-lexicon-${TAG_NAME}.zip"
|
||||||
|
echo "tag_name=${TAG_NAME}" >> $GITHUB_OUTPUT
|
||||||
|
echo "file_name=${FILE_NAME}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: 压缩项目
|
||||||
|
run: |
|
||||||
|
zip -r ${{ steps.release_info.outputs.file_name }} . -x '*.git*'
|
||||||
132
.github/workflows/server.yml
vendored
Normal file
132
.github/workflows/server.yml
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
name: Server CI/CD
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "dev", "master" ]
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
pull_request:
|
||||||
|
branches: [ "dev", "master" ]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Build server binaries
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
goos: [ linux, windows ]
|
||||||
|
goarch: [ amd64 ]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: '1.22.x'
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Download modules
|
||||||
|
run: go mod download
|
||||||
|
|
||||||
|
- name: Vet & Test
|
||||||
|
run: |
|
||||||
|
go vet ./...
|
||||||
|
go test ./... -v
|
||||||
|
|
||||||
|
- name: Build cmd/server
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p build
|
||||||
|
EXT=""
|
||||||
|
if [ "${{ matrix.goos }}" = "windows" ]; then EXT=".exe"; fi
|
||||||
|
OUT="server-${{ matrix.goos }}-${{ matrix.goarch }}${EXT}"
|
||||||
|
echo "Building $OUT"
|
||||||
|
GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} \
|
||||||
|
go build -trimpath -ldflags="-s -w" -o "build/${OUT}" ./cmd/server
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: server-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||||
|
path: build/server-${{ matrix.goos }}-${{ matrix.goarch }}*
|
||||||
|
|
||||||
|
release:
|
||||||
|
name: Release binaries
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
steps:
|
||||||
|
- name: Download artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: dist
|
||||||
|
|
||||||
|
- name: List artifacts
|
||||||
|
run: ls -R dist
|
||||||
|
|
||||||
|
- name: Create GitHub Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
files: dist/**/*
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
docker:
|
||||||
|
name: Build and push Docker image
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
|
- name: Setup Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
- name: Log in to GHCR
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Determine image name and tags
|
||||||
|
id: imagetags
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
IMAGE="ghcr.io/${{ github.repository_owner }}/sensitive-lexicon-server"
|
||||||
|
echo "IMAGE=$IMAGE" >> $GITHUB_ENV
|
||||||
|
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
||||||
|
echo "PUSH=false" >> $GITHUB_ENV
|
||||||
|
echo "TAGS=${IMAGE}:pr-${{ github.event.pull_request.number }}" >> $GITHUB_ENV
|
||||||
|
elif [ "${{ github.ref_type }}" = "tag" ]; then
|
||||||
|
echo "PUSH=true" >> $GITHUB_ENV
|
||||||
|
echo "TAGS=${IMAGE}:${{ github.ref_name }},${IMAGE}:latest" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
BRANCH="${{ github.ref_name }}"
|
||||||
|
echo "PUSH=true" >> $GITHUB_ENV
|
||||||
|
if [ "$BRANCH" = "dev" ] || [ "$BRANCH" = "master" ]; then
|
||||||
|
echo "TAGS=${IMAGE}:latest,${IMAGE}:sha-${{ github.sha }}" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "TAGS=${IMAGE}:branch-${BRANCH},${IMAGE}:sha-${{ github.sha }}" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo "Using tags: $TAGS"
|
||||||
|
|
||||||
|
- name: Build and push
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
file: ./Dockerfile
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
push: ${{ env.PUSH }}
|
||||||
|
tags: ${{ env.TAGS }}
|
||||||
45
.gitignore
vendored
Normal file
45
.gitignore
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Go build artifacts
|
||||||
|
bin/
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
out/
|
||||||
|
|
||||||
|
# Executables and shared libs
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test and coverage outputs
|
||||||
|
*.test
|
||||||
|
coverage.out
|
||||||
|
*.coverprofile
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
|
||||||
|
# Env files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
|
||||||
|
# IDE settings
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Archives and temporary files
|
||||||
|
*.zip
|
||||||
|
*.tar
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
*.7z
|
||||||
|
*.tmp
|
||||||
|
*.temp
|
||||||
|
*.swp
|
||||||
|
~*
|
||||||
37
Dockerfile
Normal file
37
Dockerfile
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# syntax=docker/dockerfile:1.4
|
||||||
|
FROM golang:1.22-alpine AS builder
|
||||||
|
WORKDIR /src
|
||||||
|
|
||||||
|
# Pre-fetch deps
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
# Copy source
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Normalize and tidy modules inside build context
|
||||||
|
RUN go mod tidy
|
||||||
|
|
||||||
|
# Build static binary for target platform
|
||||||
|
ARG TARGETOS
|
||||||
|
ARG TARGETARCH
|
||||||
|
ENV CGO_ENABLED=0
|
||||||
|
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH \
|
||||||
|
go build -trimpath -ldflags="-s -w" -o /out/server ./cmd/server
|
||||||
|
|
||||||
|
FROM gcr.io/distroless/static:nonroot
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# App binary
|
||||||
|
COPY --from=builder /out/server /app/server
|
||||||
|
|
||||||
|
# Default lexicon files
|
||||||
|
COPY Vocabulary /app/Vocabulary
|
||||||
|
|
||||||
|
# Default envs
|
||||||
|
ENV PORT=8080
|
||||||
|
ENV LEXICON_DIR=Vocabulary
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
USER nonroot
|
||||||
|
ENTRYPOINT ["/app/server"]
|
||||||
98
Jenkinsfile
vendored
Normal file
98
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
pipeline {
|
||||||
|
agent {label 'dockeragent'}
|
||||||
|
// 构建逻辑已迁移到 Dockerfile,Jenkins 不再进行本地 go build
|
||||||
|
|
||||||
|
environment {
|
||||||
|
GO111MODULE = 'on' // 开启 Modules 模式
|
||||||
|
CGO_ENABLED = '0'
|
||||||
|
APP_NAME = 'sensitive-lexicon'
|
||||||
|
REGISTRY = 'crpi-vqe38j3xeblrq0n4.cn-hangzhou.personal.cr.aliyuncs.com/go-mctown'
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Checkout') {
|
||||||
|
steps {
|
||||||
|
checkout scm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 Dockerfile 完成编译与打包,仅保留镜像构建与推送
|
||||||
|
stage('Docker Build & Push') {
|
||||||
|
steps {
|
||||||
|
withCredentials([usernamePassword(
|
||||||
|
credentialsId: 'aliyun-docker-login',
|
||||||
|
usernameVariable: 'DOCKER_USERNAME',
|
||||||
|
passwordVariable: 'DOCKER_PASSWORD'
|
||||||
|
)]) {
|
||||||
|
sh """
|
||||||
|
echo "\$DOCKER_PASSWORD" | docker login --username \$DOCKER_USERNAME --password-stdin ${env.REGISTRY.split('/')[0]}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
|
||||||
|
script {
|
||||||
|
def imageTag = "${env.REGISTRY}/${env.APP_NAME}:${env.BUILD_NUMBER}"
|
||||||
|
def latestTag = "${env.REGISTRY}/${env.APP_NAME}:latest"
|
||||||
|
|
||||||
|
sh """
|
||||||
|
ls -l
|
||||||
|
docker build -t ${imageTag} --network=host .
|
||||||
|
docker tag ${imageTag} ${latestTag}
|
||||||
|
docker push ${imageTag}
|
||||||
|
docker push ${latestTag}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Deploy All Compose Projects') {
|
||||||
|
parallel {
|
||||||
|
stage('Deploy compose1') {
|
||||||
|
agent {label 'dockeragent'}
|
||||||
|
steps {
|
||||||
|
|
||||||
|
checkout scm
|
||||||
|
sh """
|
||||||
|
pwd
|
||||||
|
ls -l
|
||||||
|
"""
|
||||||
|
dir('deploy/compose') {
|
||||||
|
script {
|
||||||
|
withCredentials([usernamePassword(
|
||||||
|
credentialsId: 'aliyun-docker-login',
|
||||||
|
usernameVariable: 'DOCKER_USERNAME',
|
||||||
|
passwordVariable: 'DOCKER_PASSWORD'
|
||||||
|
)]) {
|
||||||
|
sh """
|
||||||
|
echo "$DOCKER_PASSWORD" | docker login --username "$DOCKER_USERNAME" --password-stdin ${env.REGISTRY.split('/')[0]}
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
sh """
|
||||||
|
pwd
|
||||||
|
ls -l
|
||||||
|
docker compose -f docker-compose.yml down || true
|
||||||
|
docker compose -f docker-compose.yml pull
|
||||||
|
docker compose -f docker-compose.yml up -d --remove-orphans
|
||||||
|
"""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
cleanWs()
|
||||||
|
}
|
||||||
|
success {
|
||||||
|
echo "✅ 构建成功!"
|
||||||
|
}
|
||||||
|
failure {
|
||||||
|
echo "🔥 构建失败,请检查日志。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2024 Konsheng
|
Copyright (c) 2024~2099 Konsheng
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
1
Organized/政治类型.txt
Normal file
1
Organized/政治类型.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
109
README.md
109
README.md
@@ -1,30 +1,103 @@
|
|||||||
# 敏感词库项目 Sensitive-lexicon
|
# Sensitive-lexicon (中文敏感词库)
|
||||||
|
|
||||||

|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
> **一个持续更新的中文敏感词库,帮助开发者和内容审核者快速识别并过滤不当文本。**
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
* [简介](#简介)
|
||||||
|
* [功能特点](#功能特点)
|
||||||
|
* [目录结构](#目录结构)
|
||||||
|
* [快速开始](#快速开始)
|
||||||
|
* [集成到项目](#集成到项目)
|
||||||
|
* [贡献词汇](#贡献词汇)
|
||||||
|
* [注意事项](#注意事项)
|
||||||
|
* [开源许可](#开源许可)
|
||||||
|
* [项目支持与致谢](#项目支持与致谢)
|
||||||
|
|
||||||
## 简介
|
## 简介
|
||||||
本项目旨在创建和维护一个中文敏感词库,用于帮助开发者和内容管理者识别和过滤文本内容中的不当或不适宜的语言。通过使用本敏感词库,可以有效防止有害信息的传播,维护在线环境的健康和秩序。
|
|
||||||
|
Sensitive‑lexicon 提供了一份广泛覆盖政治、色情、暴力等敏感领域的词汇列表,方便快速嵌入任何文本审核流程,并通过社区协作保持长期更新。
|
||||||
|
|
||||||
## 功能特点
|
## 功能特点
|
||||||
- **广泛的词汇覆盖**:包含各类敏感词汇,涵盖政治、色情、暴力等多个领域。
|
|
||||||
- **定期更新**:随着社会环境和语言使用的变化,我们会定期更新词库,确保其时效性和准确性。
|
|
||||||
- **易于集成**:提供简单易懂的本地部署API接口,方便开发者在各种应用程序和系统中快速集成和使用。(开发中)
|
|
||||||
- **开源共享**:鼓励社区成员贡献和分享,共同完善敏感词库。
|
|
||||||
|
|
||||||
## 使用说明
|
* **广泛覆盖**:涵盖数万条词汇,覆盖主流敏感领域。
|
||||||
1. **集成到项目**:下载敏感词库文件,根据您的项目需求,选择合适的方式集成。
|
* **持续更新**:根据社会语境变化定期更新,保持时效性与准确性。
|
||||||
2. **调用API**:如果您希望通过API接口使用,可以参考我们的API文档进行调用。
|
* **易于集成**:纯文本格式,可在任意语言/框架中直接引用。
|
||||||
3. **贡献词汇**:我们欢迎社区成员贡献新的敏感词汇。请通过Pull Request或Issue的形式提交您的建议。
|
* **社区驱动**:欢迎 Issue / PR,携手打造更完整的词库。
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
```
|
||||||
|
Sensitive-lexicon/
|
||||||
|
├── ThirdPartyCompatibleFormats/ # 用于第三方格式
|
||||||
|
├── Organized/ # 已经进行整理的词库
|
||||||
|
├── Vocabulary/ # 词汇库
|
||||||
|
├── LICENSE # 许可证
|
||||||
|
└── README.md # 项目说明
|
||||||
|
```
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
### 集成到项目
|
||||||
|
|
||||||
|
1. 克隆或下载本仓库。
|
||||||
|
2. 在您的代码中读取 `词库中的 .txt 文件`(或您需要的分支文件)。
|
||||||
|
3. 根据业务场景,选择合适的匹配算法(如 DFA、Trie、正则表达式等)进行过滤。
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 示例:使用 Git 克隆
|
||||||
|
git clone https://github.com/Konsheng/Sensitive-lexicon.git
|
||||||
|
```
|
||||||
|
|
||||||
|
### 贡献词汇
|
||||||
|
|
||||||
|
* **Pull Request**:在 `Vocabulary/` 词汇库目录新增或修改词条,并提交 PR。
|
||||||
|
* **Issue**:如果不确定具体实现,欢迎通过 Issue 提出建议或讨论。
|
||||||
|
|
||||||
|
> **提示**:PR 请附上来源或用例,便于维护者审核。
|
||||||
|
|
||||||
## 注意事项
|
## 注意事项
|
||||||
- 在使用敏感词库时,请确保您的应用遵守当地法律法规。
|
|
||||||
- 敏感词的定义可能因文化、地区和语境而异,使用时请加以判断和适当调整。
|
* 使用时请遵守当地法律法规及平台政策。
|
||||||
|
* 敏感词定义受文化/地域/语境影响,实际应用中请结合业务需求自行评估与调整。
|
||||||
|
|
||||||
## 开源许可
|
## 开源许可
|
||||||
本项目采用[MIT许可证](LICENSE),您可以自由使用、修改和分发,但需要保留版权和许可声明。
|
|
||||||
|
|
||||||
## 联系方式
|
本项目采用 **MIT License**,在保留版权与许可声明的前提下,可自由使用、修改与分发。
|
||||||
如果您有任何问题或建议,请通过以下方式联系我们:
|
|
||||||
- Email: [konsheng@outlook.com](mailto:konsheng@outlook.com)
|
|
||||||
|
|
||||||
感谢您对本项目的支持和贡献
|
## 项目支持与致谢
|
||||||
|
|
||||||
|
* **中国数字时代** ([https://chinadigitaltimes.net](https://chinadigitaltimes.net))
|
||||||
|
* **中国农业科学院信息化办公室**
|
||||||
|
|
||||||
|
感谢所有贡献者的关注与支持!
|
||||||
|
|
||||||
|
## Star History
|
||||||
|
<a href="https://star-history.com/#konsheng/Sensitive-lexicon&Date">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=konsheng/Sensitive-lexicon&type=Date&theme=dark" />
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=konsheng/Sensitive-lexicon&type=Date" />
|
||||||
|
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=konsheng/Sensitive-lexicon&type=Date" />
|
||||||
|
</picture>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
## 运行敏感词检测服务(Fiber + fuzzy-patricia)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Windows PowerShell 示例
|
||||||
|
$env:PORT="8080"; $env:LEXICON_DIR="Vocabulary"; $env:FUZZY_MAX_DISTANCE="1"
|
||||||
|
|
||||||
|
# 构建并运行
|
||||||
|
go mod tidy
|
||||||
|
go build -o bin\server.exe ./cmd/server
|
||||||
|
./bin/server.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
- POST `/detect`
|
||||||
|
- 请求体: `{ "text": "待检测文本", "enable_fuzzy": true }`
|
||||||
|
- 响应: `{ "hits": [{"word":"...","type":"substring|fuzzy","distance":0}] }`
|
||||||
|
- POST `/reload` 重新加载 `Vocabulary` 目录
|
||||||
|
- GET `/health` 存活探针
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
76
Vocabulary/COVID-19词库.txt
Normal file
76
Vocabulary/COVID-19词库.txt
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
武汉不明肺炎
|
||||||
|
武汉海鲜市场
|
||||||
|
沙士变异
|
||||||
|
爆發sars疫情
|
||||||
|
武汉卫生委员会
|
||||||
|
p4病毒实验室
|
||||||
|
病毒感染
|
||||||
|
疫情事件
|
||||||
|
肺炎病人
|
||||||
|
武汉流行肺炎
|
||||||
|
非典性肺炎
|
||||||
|
习近平到武汉
|
||||||
|
某人亲自
|
||||||
|
雷神山
|
||||||
|
总书记
|
||||||
|
总书记
|
||||||
|
红十字会
|
||||||
|
疫情
|
||||||
|
肺炎
|
||||||
|
習近平
|
||||||
|
中央
|
||||||
|
疫情
|
||||||
|
政府
|
||||||
|
負面
|
||||||
|
疫情
|
||||||
|
習主席
|
||||||
|
凝聚力
|
||||||
|
疫情蔓延
|
||||||
|
武汉
|
||||||
|
李克强
|
||||||
|
肺炎
|
||||||
|
总理
|
||||||
|
北京
|
||||||
|
武漢
|
||||||
|
李克強
|
||||||
|
扒一扒武汉病毒所
|
||||||
|
所长的成功史
|
||||||
|
地方官+疫情+中央+隱瞞
|
||||||
|
舉行+批評中國+兩會期間+隱瞞
|
||||||
|
武漢+中共+危機+北京
|
||||||
|
共产党+肺炎+表现+统治
|
||||||
|
疫情+红会+4+政府+湖北
|
||||||
|
中国共产党+最大的威胁+这个时代
|
||||||
|
武漢+明明+病毒+人傳人
|
||||||
|
美国疾控中心+冠状病毒
|
||||||
|
菲律宾总统府感谢中国捐赠菲律宾
|
||||||
|
全面接管+10号疫情不好转+解放军
|
||||||
|
網上教學+大力+推進
|
||||||
|
封城+部隊
|
||||||
|
政府+做出+测序+病毒
|
||||||
|
为辅+西医+冠状病毒
|
||||||
|
省委书记+通报+专家组+病毒
|
||||||
|
断崖式下跌+疫情防控
|
||||||
|
發起罷工+五大訴求+員工陣線
|
||||||
|
香港+林鄭+呼籲+病毒
|
||||||
|
香港+港府+衞生防護+港人
|
||||||
|
大陸+台灣+病毒+外交部
|
||||||
|
口罩+台灣+出口+國家
|
||||||
|
口罩+台灣+政府+中國大陸
|
||||||
|
澳門+政府+戴口罩
|
||||||
|
武漢肺炎疫情失控
|
||||||
|
死亡病例+肺炎+死亡人數
|
||||||
|
武漢+感染+十幾萬
|
||||||
|
上海+背景+药物+病毒
|
||||||
|
毒城+武漢
|
||||||
|
武汉+发生+人传人+病毒
|
||||||
|
肺炎+疾病预防控制+病毒+医学期刊
|
||||||
|
有关+疾病控制+旅行限制+病毒
|
||||||
|
疫情+颜色革命+李文亮
|
||||||
|
聲音+人傳人+李文亮
|
||||||
|
疫情+病毒+李文亮+中央
|
||||||
|
冠状病毒+人传人+李文亮
|
||||||
|
监察委+确诊+李文亮
|
||||||
|
武漢+光復
|
||||||
|
湖北+五大诉求
|
||||||
|
武汉+五大诉求
|
||||||
6414
Vocabulary/GFW补充词库.txt
Normal file
6414
Vocabulary/GFW补充词库.txt
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
|||||||
|
力工
|
||||||
穴海
|
穴海
|
||||||
协警
|
协警
|
||||||
纳米比亚
|
纳米比亚
|
||||||
|
|||||||
123
Vocabulary/广告类型.txt
Normal file
123
Vocabulary/广告类型.txt
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
兼职
|
||||||
|
招聘
|
||||||
|
网络
|
||||||
|
QQ
|
||||||
|
招聘
|
||||||
|
有意者
|
||||||
|
到货
|
||||||
|
本店
|
||||||
|
代购
|
||||||
|
扣扣
|
||||||
|
客服
|
||||||
|
微店
|
||||||
|
兼职
|
||||||
|
兼值
|
||||||
|
淘宝
|
||||||
|
小姐
|
||||||
|
妓女
|
||||||
|
包夜
|
||||||
|
3P
|
||||||
|
LY
|
||||||
|
JS
|
||||||
|
狼友
|
||||||
|
技师
|
||||||
|
推油
|
||||||
|
胸推
|
||||||
|
BT
|
||||||
|
毒龙
|
||||||
|
口爆
|
||||||
|
兼职
|
||||||
|
楼凤
|
||||||
|
足交
|
||||||
|
口暴
|
||||||
|
口交
|
||||||
|
全套
|
||||||
|
SM
|
||||||
|
桑拿
|
||||||
|
吞精
|
||||||
|
咪咪
|
||||||
|
婊子
|
||||||
|
乳方
|
||||||
|
操逼
|
||||||
|
全职
|
||||||
|
性伴侣
|
||||||
|
网购
|
||||||
|
网络工作
|
||||||
|
代理
|
||||||
|
专业代理
|
||||||
|
帮忙点一下
|
||||||
|
帮忙点下
|
||||||
|
请点击进入
|
||||||
|
详情请进入
|
||||||
|
私人侦探
|
||||||
|
私家侦探
|
||||||
|
针孔摄象
|
||||||
|
调查婚外情
|
||||||
|
信用卡提现
|
||||||
|
无抵押贷款
|
||||||
|
广告代理
|
||||||
|
原音铃声
|
||||||
|
借腹生子
|
||||||
|
找个妈妈
|
||||||
|
找个爸爸
|
||||||
|
代孕妈妈
|
||||||
|
代生孩子
|
||||||
|
代开发票
|
||||||
|
腾讯客服电话
|
||||||
|
销售热线
|
||||||
|
免费订购热线
|
||||||
|
低价出售
|
||||||
|
款到发货
|
||||||
|
回复可见
|
||||||
|
连锁加盟
|
||||||
|
加盟连锁
|
||||||
|
免费二级域名
|
||||||
|
免费使用
|
||||||
|
免费索取
|
||||||
|
蚁力神
|
||||||
|
婴儿汤
|
||||||
|
售肾
|
||||||
|
刻章办
|
||||||
|
买小车
|
||||||
|
套牌车
|
||||||
|
玛雅网
|
||||||
|
电脑传讯
|
||||||
|
视频来源
|
||||||
|
下载速度
|
||||||
|
高清在线
|
||||||
|
全集在线
|
||||||
|
在线播放
|
||||||
|
txt下载
|
||||||
|
六位qq
|
||||||
|
6位qq
|
||||||
|
位的qq
|
||||||
|
个qb
|
||||||
|
送qb
|
||||||
|
用刀横向切腹
|
||||||
|
完全自杀手册
|
||||||
|
四海帮
|
||||||
|
足球投注
|
||||||
|
地下钱庄
|
||||||
|
中国复兴党
|
||||||
|
阿波罗网
|
||||||
|
曾道人
|
||||||
|
六合彩
|
||||||
|
改卷内幕
|
||||||
|
替考试
|
||||||
|
隐形耳机
|
||||||
|
出售答案
|
||||||
|
考中答案
|
||||||
|
答an
|
||||||
|
da案
|
||||||
|
资金周转
|
||||||
|
救市
|
||||||
|
股市圈钱
|
||||||
|
崩盘
|
||||||
|
资金短缺
|
||||||
|
证监会
|
||||||
|
质押贷款
|
||||||
|
小额贷款
|
||||||
|
周小川
|
||||||
|
刘明康
|
||||||
|
尚福林
|
||||||
|
孔丹
|
||||||
326
Vocabulary/政治类型.txt
Normal file
326
Vocabulary/政治类型.txt
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
习近平
|
||||||
|
平近习
|
||||||
|
xjp
|
||||||
|
习太子
|
||||||
|
习明泽
|
||||||
|
老习
|
||||||
|
温家宝
|
||||||
|
温加宝
|
||||||
|
温x
|
||||||
|
温jia宝
|
||||||
|
温宝宝
|
||||||
|
温加饱
|
||||||
|
温加保
|
||||||
|
张培莉
|
||||||
|
温云松
|
||||||
|
温如春
|
||||||
|
温jb
|
||||||
|
胡温
|
||||||
|
胡x
|
||||||
|
胡jt
|
||||||
|
胡boss
|
||||||
|
胡总
|
||||||
|
胡王八
|
||||||
|
hujintao
|
||||||
|
胡jintao
|
||||||
|
胡j涛
|
||||||
|
胡惊涛
|
||||||
|
胡景涛
|
||||||
|
胡紧掏
|
||||||
|
湖紧掏
|
||||||
|
胡紧套
|
||||||
|
锦涛
|
||||||
|
hjt
|
||||||
|
胡派
|
||||||
|
胡主席
|
||||||
|
刘永清
|
||||||
|
胡海峰
|
||||||
|
胡海清
|
||||||
|
江泽民
|
||||||
|
民泽江
|
||||||
|
江胡
|
||||||
|
江哥
|
||||||
|
江主席
|
||||||
|
江书记
|
||||||
|
江浙闽
|
||||||
|
江沢民
|
||||||
|
江浙民
|
||||||
|
择民
|
||||||
|
则民
|
||||||
|
茳泽民
|
||||||
|
zemin
|
||||||
|
ze民
|
||||||
|
老江
|
||||||
|
老j
|
||||||
|
江core
|
||||||
|
江x
|
||||||
|
江派
|
||||||
|
江zm
|
||||||
|
jzm
|
||||||
|
江戏子
|
||||||
|
江蛤蟆
|
||||||
|
江某某
|
||||||
|
江贼
|
||||||
|
江猪
|
||||||
|
江氏集团
|
||||||
|
江绵恒
|
||||||
|
江绵康
|
||||||
|
王冶坪
|
||||||
|
江泽慧
|
||||||
|
邓小平
|
||||||
|
平小邓
|
||||||
|
xiao平
|
||||||
|
邓xp
|
||||||
|
邓晓平
|
||||||
|
邓朴方
|
||||||
|
邓榕
|
||||||
|
邓质方
|
||||||
|
毛泽东
|
||||||
|
猫泽东
|
||||||
|
猫则东
|
||||||
|
猫贼洞
|
||||||
|
毛zd
|
||||||
|
毛zx
|
||||||
|
z东
|
||||||
|
ze东
|
||||||
|
泽d
|
||||||
|
zedong
|
||||||
|
毛太祖
|
||||||
|
毛相
|
||||||
|
主席画像
|
||||||
|
改革历程
|
||||||
|
朱镕基
|
||||||
|
朱容基
|
||||||
|
朱镕鸡
|
||||||
|
朱容鸡
|
||||||
|
朱云来
|
||||||
|
李鹏
|
||||||
|
李peng
|
||||||
|
里鹏
|
||||||
|
李月月鸟
|
||||||
|
李小鹏
|
||||||
|
李小琳
|
||||||
|
华主席
|
||||||
|
华国
|
||||||
|
国锋
|
||||||
|
国峰
|
||||||
|
锋同志
|
||||||
|
白春礼
|
||||||
|
薄熙来
|
||||||
|
薄一波
|
||||||
|
蔡赴朝
|
||||||
|
蔡武
|
||||||
|
曹刚川
|
||||||
|
常万全
|
||||||
|
陈炳德
|
||||||
|
陈德铭
|
||||||
|
陈建国
|
||||||
|
陈良宇
|
||||||
|
陈绍基
|
||||||
|
陈同海
|
||||||
|
陈至立
|
||||||
|
戴秉国
|
||||||
|
丁一平
|
||||||
|
董建华
|
||||||
|
杜德印
|
||||||
|
杜世成
|
||||||
|
傅锐
|
||||||
|
郭伯雄
|
||||||
|
郭金龙
|
||||||
|
贺国强
|
||||||
|
胡春华
|
||||||
|
耀邦
|
||||||
|
华建敏
|
||||||
|
黄华华
|
||||||
|
黄丽满
|
||||||
|
黄兴国
|
||||||
|
回良玉
|
||||||
|
贾庆林
|
||||||
|
贾廷安
|
||||||
|
靖志远
|
||||||
|
李长春
|
||||||
|
李春城
|
||||||
|
李建国
|
||||||
|
李克强
|
||||||
|
李岚清
|
||||||
|
李沛瑶
|
||||||
|
李荣融
|
||||||
|
李瑞环
|
||||||
|
李铁映
|
||||||
|
李先念
|
||||||
|
李学举
|
||||||
|
李源潮
|
||||||
|
栗智
|
||||||
|
梁光烈
|
||||||
|
廖锡龙
|
||||||
|
林树森
|
||||||
|
林炎志
|
||||||
|
林左鸣
|
||||||
|
令计划
|
||||||
|
柳斌杰
|
||||||
|
刘奇葆
|
||||||
|
刘少奇
|
||||||
|
刘延东
|
||||||
|
刘云山
|
||||||
|
刘志军
|
||||||
|
龙新民
|
||||||
|
路甬祥
|
||||||
|
罗箭
|
||||||
|
吕祖善
|
||||||
|
马飚
|
||||||
|
马恺
|
||||||
|
孟建柱
|
||||||
|
欧广源
|
||||||
|
强卫
|
||||||
|
沈跃跃
|
||||||
|
宋平顺
|
||||||
|
粟戎生
|
||||||
|
苏树林
|
||||||
|
孙家正
|
||||||
|
铁凝
|
||||||
|
屠光绍
|
||||||
|
王东明
|
||||||
|
汪东兴
|
||||||
|
王鸿举
|
||||||
|
王沪宁
|
||||||
|
王乐泉
|
||||||
|
王洛林
|
||||||
|
王岐山
|
||||||
|
王胜俊
|
||||||
|
王太华
|
||||||
|
王学军
|
||||||
|
王兆国
|
||||||
|
王振华
|
||||||
|
吴邦国
|
||||||
|
吴定富
|
||||||
|
吴官正
|
||||||
|
无官正
|
||||||
|
吴胜利
|
||||||
|
吴仪
|
||||||
|
奚国华
|
||||||
|
习仲勋
|
||||||
|
徐才厚
|
||||||
|
许其亮
|
||||||
|
徐绍史
|
||||||
|
杨洁篪
|
||||||
|
叶剑英
|
||||||
|
由喜贵
|
||||||
|
于幼军
|
||||||
|
俞正声
|
||||||
|
袁纯清
|
||||||
|
曾培炎
|
||||||
|
曾庆红
|
||||||
|
曾宪梓
|
||||||
|
曾荫权
|
||||||
|
张德江
|
||||||
|
张定发
|
||||||
|
张高丽
|
||||||
|
张立昌
|
||||||
|
张荣坤
|
||||||
|
张志国
|
||||||
|
赵洪祝
|
||||||
|
紫阳
|
||||||
|
周生贤
|
||||||
|
周永康
|
||||||
|
朱海仑
|
||||||
|
中南海
|
||||||
|
大陆当局
|
||||||
|
中国当局
|
||||||
|
北京当局
|
||||||
|
共产党
|
||||||
|
党产共
|
||||||
|
共贪党
|
||||||
|
阿共
|
||||||
|
产党共
|
||||||
|
公产党
|
||||||
|
工产党
|
||||||
|
共c党
|
||||||
|
共x党
|
||||||
|
共铲
|
||||||
|
供产
|
||||||
|
共惨
|
||||||
|
供铲党
|
||||||
|
供铲谠
|
||||||
|
供铲裆
|
||||||
|
共残党
|
||||||
|
共残主义
|
||||||
|
共产主义的幽灵
|
||||||
|
拱铲
|
||||||
|
老共
|
||||||
|
中共
|
||||||
|
中珙
|
||||||
|
中gong
|
||||||
|
gc党
|
||||||
|
贡挡
|
||||||
|
gong党
|
||||||
|
g产
|
||||||
|
狗产蛋
|
||||||
|
共残裆
|
||||||
|
恶党
|
||||||
|
邪党
|
||||||
|
共产专制
|
||||||
|
共产王朝
|
||||||
|
裆中央
|
||||||
|
土共
|
||||||
|
土g
|
||||||
|
共狗
|
||||||
|
g匪
|
||||||
|
共匪
|
||||||
|
仇共
|
||||||
|
政府
|
||||||
|
症腐
|
||||||
|
政腐
|
||||||
|
政付
|
||||||
|
正府
|
||||||
|
政俯
|
||||||
|
政f
|
||||||
|
zhengfu
|
||||||
|
政zhi
|
||||||
|
挡中央
|
||||||
|
档中央
|
||||||
|
中央领导
|
||||||
|
中国zf
|
||||||
|
中央zf
|
||||||
|
国wu院
|
||||||
|
中华帝国
|
||||||
|
gong和
|
||||||
|
大陆官方
|
||||||
|
北京政权
|
||||||
|
江泽民
|
||||||
|
胡锦涛
|
||||||
|
温家宝
|
||||||
|
习近平
|
||||||
|
习仲勋
|
||||||
|
贺国强
|
||||||
|
贺子珍
|
||||||
|
周永康
|
||||||
|
李长春
|
||||||
|
李德生
|
||||||
|
王岐山
|
||||||
|
姚依林
|
||||||
|
回良玉
|
||||||
|
李源潮
|
||||||
|
李干成
|
||||||
|
戴秉国
|
||||||
|
黄镇
|
||||||
|
刘延东
|
||||||
|
刘瑞龙
|
||||||
|
俞正声
|
||||||
|
黄敬
|
||||||
|
薄熙
|
||||||
|
薄一波
|
||||||
|
周小川
|
||||||
|
周建南
|
||||||
|
温云松
|
||||||
|
徐明
|
||||||
|
江泽慧
|
||||||
|
江绵恒
|
||||||
|
江绵康
|
||||||
|
李小鹏
|
||||||
|
李鹏
|
||||||
|
李小琳
|
||||||
|
朱云来
|
||||||
|
朱容基
|
||||||
|
法轮功
|
||||||
|
李洪志
|
||||||
|
新疆骚乱
|
||||||
437
Vocabulary/涉枪涉爆.txt
Normal file
437
Vocabulary/涉枪涉爆.txt
Normal file
@@ -0,0 +1,437 @@
|
|||||||
|
出售雷管
|
||||||
|
炸药
|
||||||
|
炸药
|
||||||
|
出售炸药
|
||||||
|
出售炸药 电话
|
||||||
|
制作火药配方
|
||||||
|
炸药出售
|
||||||
|
出售雷管炸药
|
||||||
|
火药配方
|
||||||
|
在家里做原子弹
|
||||||
|
硝酸甘油炸弹制作
|
||||||
|
TNT 炸弹的制作
|
||||||
|
硝铵炸药配方
|
||||||
|
硝酸甘油制作
|
||||||
|
炸弹配方
|
||||||
|
简易炸药
|
||||||
|
火药制作简易炸弹
|
||||||
|
炸弹制作
|
||||||
|
硝酸甘油
|
||||||
|
硝酸甘油炸弹制作方法
|
||||||
|
手把手教你做炸弹
|
||||||
|
恐怖分子傻瓜手册
|
||||||
|
氢弹手工制作方法
|
||||||
|
起爆器
|
||||||
|
自制燃烧弹
|
||||||
|
燃烧弹
|
||||||
|
弹药制造方法
|
||||||
|
液体炸药配方
|
||||||
|
炸药配方与制作
|
||||||
|
自制炸药配方
|
||||||
|
tnt炸药成分
|
||||||
|
炸药的制作
|
||||||
|
tnt炸药配方
|
||||||
|
各种炸药配方大全
|
||||||
|
炸药的成分
|
||||||
|
燃烧弹的制作方
|
||||||
|
黑火药的配方
|
||||||
|
黑火药的制作
|
||||||
|
黑火药比例
|
||||||
|
燃烧弹 制作
|
||||||
|
黑火药配方比例
|
||||||
|
黑火药的成分
|
||||||
|
原子弹配方
|
||||||
|
原子弹DIY教程
|
||||||
|
C4炸药
|
||||||
|
雷管出售
|
||||||
|
制作硝化甘油
|
||||||
|
DIY核弹
|
||||||
|
核弹制作方法
|
||||||
|
原子弹制作手册
|
||||||
|
简易原子弹教程
|
||||||
|
黑火药配方
|
||||||
|
自制炸药方法
|
||||||
|
教你怎么用土办法做武器
|
||||||
|
莫洛托夫鸡尾酒的配方
|
||||||
|
zz炸弹的制作方法
|
||||||
|
C4炸药的成分
|
||||||
|
炸药制造生产工艺
|
||||||
|
原子弹制造完全手册
|
||||||
|
「红烧兔子」大餐
|
||||||
|
汽车炸弹制作
|
||||||
|
人体炸弹制作流程
|
||||||
|
炸弹制作从入门
|
||||||
|
鸡尾酒炸弹制作
|
||||||
|
集束炸弹制作
|
||||||
|
硝酸铵的简便制取方法
|
||||||
|
莫洛托夫燃烧弹
|
||||||
|
塑胶炸弹
|
||||||
|
用火药混合塑料
|
||||||
|
高性能爆炸物质混合
|
||||||
|
原子弹 制作方法
|
||||||
|
手教你制作原子弹
|
||||||
|
轻型巡航导弹的制作
|
||||||
|
黑索金的制造过程
|
||||||
|
Zha药制造进程
|
||||||
|
购买自爆材料
|
||||||
|
可塑炸弹制作方法
|
||||||
|
C4塑胶炸药
|
||||||
|
水浴法制TNT
|
||||||
|
简易核弹头的制造
|
||||||
|
高爆炸药的基本配方
|
||||||
|
如何制硝化甘油
|
||||||
|
燃烧剂的简易制备
|
||||||
|
简易大威力炸弹
|
||||||
|
炸弹制作入门
|
||||||
|
硝酸甘油炸药制作
|
||||||
|
基本配方是硝酸甘
|
||||||
|
燃烧剂的简易制作
|
||||||
|
制作性能优良的燃烧弹
|
||||||
|
酸甘油炸药
|
||||||
|
简易导弹制作
|
||||||
|
核弹头的制造
|
||||||
|
可塑炸弹制作
|
||||||
|
炸药硝酸甘油制法
|
||||||
|
原子弹制作方法
|
||||||
|
火药的配方
|
||||||
|
手教你做原子弹
|
||||||
|
怎么用土办法做武器
|
||||||
|
手把手教你制作原子弹
|
||||||
|
燃烧弹的制作方法
|
||||||
|
怎么自制燃烧弹
|
||||||
|
TNT炸弹制作
|
||||||
|
高爆炸药基本配方
|
||||||
|
爆破和杀伤燃烧弹
|
||||||
|
炸弹制作从入门到精
|
||||||
|
写的炸弹制作教程
|
||||||
|
原子弹制作 方法
|
||||||
|
教你制作原子弹
|
||||||
|
下硝化甘油的制作方法
|
||||||
|
DIY原子弹
|
||||||
|
原子弹制作
|
||||||
|
炸药及其制造方法
|
||||||
|
ATOM弹制造
|
||||||
|
三分钟教你原子弹
|
||||||
|
火药原理
|
||||||
|
简易炸弹
|
||||||
|
简易燃烧弹
|
||||||
|
土炸药成份
|
||||||
|
你怎么用土办法做武器
|
||||||
|
燃烧弹制作
|
||||||
|
燃烧瓶的制作方法
|
||||||
|
炸弹制作手册 硫酸
|
||||||
|
原子弹制作方法DIY
|
||||||
|
汽油三分之一白糖混合
|
||||||
|
炸药的制作配方
|
||||||
|
燃烧弹的制作方
|
||||||
|
炸药的配方
|
||||||
|
如何自制燃烧弹
|
||||||
|
标准炸弹教程
|
||||||
|
黑火药和硝酸钾农药混合
|
||||||
|
恐怖分子自己制造炸弹
|
||||||
|
手柄制作炸弹引爆器
|
||||||
|
制作炸弹首先要
|
||||||
|
燃烧瓶制作
|
||||||
|
出售炸药QQ
|
||||||
|
出售气枪
|
||||||
|
出售气枪 QQ
|
||||||
|
出售气枪 电话
|
||||||
|
出售手枪
|
||||||
|
出售手枪 QQ
|
||||||
|
出售手枪 电话
|
||||||
|
出售猎枪
|
||||||
|
出售猎枪 QQ
|
||||||
|
出售猎枪 电话
|
||||||
|
出售汽枪
|
||||||
|
出售步枪
|
||||||
|
出售狙击枪
|
||||||
|
出售手狗
|
||||||
|
出售气狗
|
||||||
|
出售猎狗
|
||||||
|
【手枪出售】联系电话
|
||||||
|
64式手枪出售
|
||||||
|
92式手枪出售
|
||||||
|
出售:高仿真枪
|
||||||
|
出售54式手枪
|
||||||
|
出售M1911
|
||||||
|
出售各类猎狗
|
||||||
|
出售国产军用54手枪
|
||||||
|
出售火枪 –游戏
|
||||||
|
出售进口金属枪模
|
||||||
|
出售仿真枪
|
||||||
|
出售麻醉枪免收任何定金
|
||||||
|
出售手枪=货到付款
|
||||||
|
出售外国枪模
|
||||||
|
出售袖珍手枪
|
||||||
|
娥眉气枪出售
|
||||||
|
防身手枪QQ
|
||||||
|
防身武器手枪
|
||||||
|
仿真枪QQ
|
||||||
|
钢珠枪小口径步枪
|
||||||
|
高压狗QQ
|
||||||
|
高压气枪,气枪子弹
|
||||||
|
高压气枪|电狗专卖
|
||||||
|
高压气枪|气枪货到付款
|
||||||
|
高压气枪专卖店
|
||||||
|
各类军用枪
|
||||||
|
各类军用枪支
|
||||||
|
各式气枪出售
|
||||||
|
工字牌气枪出售专卖
|
||||||
|
气枪
|
||||||
|
工字汽狗麻醉枪
|
||||||
|
供应军用手枪
|
||||||
|
供应汽枪
|
||||||
|
购买枪支QQ
|
||||||
|
国产汽狗专卖|气枪货
|
||||||
|
集团出售手枪
|
||||||
|
集团出售手枪气枪
|
||||||
|
进口气枪,气枪子弹
|
||||||
|
军用54出售
|
||||||
|
军用77出售
|
||||||
|
军用手枪钢珠枪
|
||||||
|
里有汽枪出售
|
||||||
|
猎枪出售/枪
|
||||||
|
猎枪仿真枪QQ
|
||||||
|
猎枪麻醉枪钢珠枪
|
||||||
|
猎枪哪里有卖
|
||||||
|
猎枪手枪买卖
|
||||||
|
猎枪销售手枪销售气枪
|
||||||
|
猎枪专卖店
|
||||||
|
猎枪子弹底火专卖
|
||||||
|
麻醉枪出售可验货
|
||||||
|
麻醉枪猎枪军用
|
||||||
|
买卖54狗
|
||||||
|
买卖64狗
|
||||||
|
买卖警察枪支
|
||||||
|
买卖军狗
|
||||||
|
买卖军用枪支
|
||||||
|
卖64手枪
|
||||||
|
卖92手枪
|
||||||
|
卖钢珠枪QQ
|
||||||
|
哪里能买到自制手枪
|
||||||
|
哪里有钢珠枪
|
||||||
|
哪里有连发猎枪买卖
|
||||||
|
哪里有卖双管猎
|
||||||
|
哪里有气枪卖
|
||||||
|
哪里有枪出售
|
||||||
|
哪里有真枪出售
|
||||||
|
哪里有真枪卖买
|
||||||
|
哪能买到真枪
|
||||||
|
期出售手枪气枪猎
|
||||||
|
气狗 高压气枪
|
||||||
|
气狗出售 进口气狗
|
||||||
|
气枪专卖网
|
||||||
|
气枪/出售/专卖网
|
||||||
|
气枪/猎枪/钢珠枪
|
||||||
|
气枪仿真枪出售
|
||||||
|
气枪购买|气枪组装
|
||||||
|
气枪货到付款,汽狗出售
|
||||||
|
气枪价格 仿真气枪
|
||||||
|
气枪价格,气枪专卖店
|
||||||
|
气枪看货加QQ
|
||||||
|
气枪联系QQ
|
||||||
|
气枪猎枪麻醉枪
|
||||||
|
气枪迷魂药
|
||||||
|
汽狗高压汽枪
|
||||||
|
铅弹 上海工字气枪
|
||||||
|
全金属仿真枪专卖
|
||||||
|
热武器QQ
|
||||||
|
三箭气枪出售
|
||||||
|
手枪气* 枪猎
|
||||||
|
手槍买卖自制手枪
|
||||||
|
售枪购买手枪
|
||||||
|
售手枪QQ
|
||||||
|
司马仿真枪模型QQ
|
||||||
|
淘宝气枪货到付款
|
||||||
|
提供气狗专卖店
|
||||||
|
提供专业及时的气狗
|
||||||
|
秃鹰气枪货到付款
|
||||||
|
锡峰气枪出售
|
||||||
|
仙鹤气枪出售
|
||||||
|
销售/专卖/买卖77式手枪
|
||||||
|
销售电手狗
|
||||||
|
销售气手狗
|
||||||
|
销售小口径步枪
|
||||||
|
销售运动步枪
|
||||||
|
小口径秃鹰沙漠
|
||||||
|
有军用枪支出售
|
||||||
|
长期出 售手枪
|
||||||
|
折叠狗QQ
|
||||||
|
转让 猎枪
|
||||||
|
子弹货到付款
|
||||||
|
自制手枪哪里买
|
||||||
|
自制手枪哪里有卖
|
||||||
|
阻击枪/汽枪/高压气枪
|
||||||
|
组装手枪
|
||||||
|
最新销售汽狗
|
||||||
|
出售警用手铐|仿真枪
|
||||||
|
猎枪|真枪
|
||||||
|
手枪|阻击枪
|
||||||
|
弓弩专营
|
||||||
|
弓弩专卖网货到付款
|
||||||
|
弓弩专卖网
|
||||||
|
弓弩专卖货到付款
|
||||||
|
弓弩专卖店网
|
||||||
|
弓弩专卖店
|
||||||
|
弓弩专卖
|
||||||
|
弓弩制作
|
||||||
|
弓弩直销
|
||||||
|
弓弩有限公司
|
||||||
|
弓弩营销中心
|
||||||
|
弓弩一百专卖店
|
||||||
|
弓弩销售
|
||||||
|
弓弩网
|
||||||
|
弓弩网
|
||||||
|
弓弩图纸
|
||||||
|
弓弩特许经销
|
||||||
|
弓弩狩猎网
|
||||||
|
自制手弩
|
||||||
|
追风弓弩麻醉箭专卖
|
||||||
|
专业弓弩网
|
||||||
|
中国战神军用弓弩
|
||||||
|
中国弩弓专卖
|
||||||
|
中国弓弩专卖网
|
||||||
|
中国弓弩直销
|
||||||
|
中国弓弩网
|
||||||
|
中国弓弩狩猎网
|
||||||
|
中国弓驽网
|
||||||
|
制作简易弓弩
|
||||||
|
郑州弓弩专卖
|
||||||
|
赵氏弓弩专卖网
|
||||||
|
赵氏弓弩专卖店
|
||||||
|
赵氏弓弩专卖
|
||||||
|
赵氏弓弩销售
|
||||||
|
小型弓弩专卖店
|
||||||
|
小猎人弓弩网
|
||||||
|
狩猎器材弓弩专卖
|
||||||
|
狩猎器材弓弩
|
||||||
|
狩猎弓弩专卖网
|
||||||
|
狩猎弓弩专卖
|
||||||
|
狩猎弓弩麻醉箭
|
||||||
|
手枪式折叠三用弩
|
||||||
|
三利达弓弩专卖网
|
||||||
|
三利达弓弩直营
|
||||||
|
三利达弓弩配件
|
||||||
|
三步倒药箭批发
|
||||||
|
三步倒弩箭专卖
|
||||||
|
三步倒麻醉弩箭销售
|
||||||
|
三步倒麻醉箭专卖
|
||||||
|
三步倒麻醉箭
|
||||||
|
三步倒捕狗药
|
||||||
|
军用弓弩专卖网
|
||||||
|
军用弓弩专卖店
|
||||||
|
军用弓弩批发
|
||||||
|
军用弓弩公司
|
||||||
|
供应三利达弓弩麻醉箭
|
||||||
|
供应三步倒麻醉箭
|
||||||
|
供应秦氏弓弩
|
||||||
|
供应弩用麻醉箭
|
||||||
|
供应弩捕狗箭
|
||||||
|
供应麻醉箭三步倒
|
||||||
|
供应麻醉箭批发
|
||||||
|
供应麻醉箭
|
||||||
|
供应军用弩折叠弩
|
||||||
|
供应军用弓弩专卖
|
||||||
|
供应精品弓弩
|
||||||
|
供应弓弩麻醉箭
|
||||||
|
供应弓弩
|
||||||
|
供应钢珠弓弩
|
||||||
|
弓弩商城专卖
|
||||||
|
弓弩商城
|
||||||
|
弓弩亲兄弟货到付款
|
||||||
|
弓弩批发
|
||||||
|
弓弩免定金货到付款
|
||||||
|
弓弩麻醉箭
|
||||||
|
弓弩麻醉镖
|
||||||
|
弓弩论坛
|
||||||
|
钢珠弓弩专卖网
|
||||||
|
钢珠弓弩专卖店
|
||||||
|
打狗弓弩三步倒
|
||||||
|
麻醉弓弩专卖店
|
||||||
|
出售军刀
|
||||||
|
出售军刺
|
||||||
|
出售弹簧刀
|
||||||
|
出售三棱刀
|
||||||
|
出售跳刀
|
||||||
|
军刀网
|
||||||
|
南方军刀网
|
||||||
|
户外军刀网
|
||||||
|
三棱军刺专卖
|
||||||
|
出售开山刀军刺
|
||||||
|
西点军刀网
|
||||||
|
军刀专 卖
|
||||||
|
戈博军刀
|
||||||
|
阿兰德龙户外
|
||||||
|
出售军品军刀
|
||||||
|
勃朗宁军刀
|
||||||
|
军刀军品网
|
||||||
|
阿兰得龙野营刀具网
|
||||||
|
出售军刺军刀
|
||||||
|
警用刀具出售
|
||||||
|
折刀专卖网
|
||||||
|
阳江军品军刀网
|
||||||
|
野营刀专卖
|
||||||
|
砍刀精品折刀专卖
|
||||||
|
匕首蝴蝶甩刀专卖
|
||||||
|
军刀专卖军刺
|
||||||
|
军刀专卖刀具批发
|
||||||
|
军刀图片砍刀
|
||||||
|
军刀网军刀专卖
|
||||||
|
军刀价格军用刀具
|
||||||
|
军品军刺网
|
||||||
|
军刀军刺甩棍
|
||||||
|
阳江刀具批发网
|
||||||
|
北方先锋军刀
|
||||||
|
正品军刺出售
|
||||||
|
野营军刀出售
|
||||||
|
开山刀砍刀出售
|
||||||
|
仿品军刺出售
|
||||||
|
军刀直刀专卖
|
||||||
|
手工猎刀专卖
|
||||||
|
自动跳刀专卖
|
||||||
|
军刀电棍销售
|
||||||
|
军刀甩棍销售
|
||||||
|
美国军刀出售
|
||||||
|
极端武力折刀
|
||||||
|
防卫棍刀户外刀具
|
||||||
|
阿兰德龙野营刀
|
||||||
|
仿品军刺网
|
||||||
|
野营砍刀户外军刀
|
||||||
|
手工猎刀户外刀具
|
||||||
|
中国户外刀具网
|
||||||
|
西点军品军刀网
|
||||||
|
野营开山刀军刺
|
||||||
|
三利达弓弩军刀
|
||||||
|
尼泊尔军刀出售
|
||||||
|
防卫野营砍刀出售
|
||||||
|
防卫著名军刀出售
|
||||||
|
防卫棍刀出售
|
||||||
|
防卫甩棍出售
|
||||||
|
防卫电棍出售
|
||||||
|
军刺野营砍刀出售
|
||||||
|
著名精品折刀出售
|
||||||
|
战术军刀出售
|
||||||
|
刺刀专卖网
|
||||||
|
户外军刀出售
|
||||||
|
阳江刀具直销网
|
||||||
|
冷钢刀具直销网
|
||||||
|
防卫刀具直销网
|
||||||
|
极端武力直销网
|
||||||
|
刀具直销网
|
||||||
|
军刀直销网
|
||||||
|
直刀匕首直销网
|
||||||
|
军刀匕首直销网
|
||||||
|
折刀砍刀军品网
|
||||||
|
野营刀具军品网
|
||||||
|
阳江刀具军品网
|
||||||
|
冷钢刀具军品网
|
||||||
|
防卫刀具军品网
|
||||||
|
极端武力军品网
|
||||||
|
军用刀具军品网
|
||||||
|
军刀直刀军品网
|
||||||
|
折刀砍刀专卖
|
||||||
|
野营刀具专卖
|
||||||
|
阳江刀具专卖
|
||||||
|
冷钢刀具专卖
|
||||||
|
防卫刀具专卖
|
||||||
|
出售美军现役军刀
|
||||||
7746
Vocabulary/网易前端过滤敏感词库.txt
Normal file
7746
Vocabulary/网易前端过滤敏感词库.txt
Normal file
File diff suppressed because it is too large
Load Diff
304
Vocabulary/色情类型.txt
Normal file
304
Vocabulary/色情类型.txt
Normal file
@@ -0,0 +1,304 @@
|
|||||||
|
爱液
|
||||||
|
按摩棒
|
||||||
|
拔出来
|
||||||
|
爆草
|
||||||
|
包二奶
|
||||||
|
暴干
|
||||||
|
暴奸
|
||||||
|
暴乳
|
||||||
|
爆乳
|
||||||
|
暴淫
|
||||||
|
被操
|
||||||
|
被插
|
||||||
|
被干
|
||||||
|
逼奸
|
||||||
|
仓井空
|
||||||
|
插暴
|
||||||
|
操逼
|
||||||
|
操黑
|
||||||
|
操烂
|
||||||
|
肏你
|
||||||
|
肏死
|
||||||
|
操死
|
||||||
|
操我
|
||||||
|
厕奴
|
||||||
|
插比
|
||||||
|
插b
|
||||||
|
插逼
|
||||||
|
插进
|
||||||
|
插你
|
||||||
|
插我
|
||||||
|
插阴
|
||||||
|
潮吹
|
||||||
|
潮喷
|
||||||
|
成人电影
|
||||||
|
成人论坛
|
||||||
|
成人色情
|
||||||
|
成人网站
|
||||||
|
成人文学
|
||||||
|
成人小说
|
||||||
|
艳情小说
|
||||||
|
成人游戏
|
||||||
|
吃精
|
||||||
|
抽插
|
||||||
|
春药
|
||||||
|
大波
|
||||||
|
大力抽送
|
||||||
|
大乳
|
||||||
|
荡妇
|
||||||
|
荡女
|
||||||
|
盗撮
|
||||||
|
发浪
|
||||||
|
放尿
|
||||||
|
肥逼
|
||||||
|
粉穴
|
||||||
|
风月大陆
|
||||||
|
干死你
|
||||||
|
干穴
|
||||||
|
肛交
|
||||||
|
肛门
|
||||||
|
龟头
|
||||||
|
裹本
|
||||||
|
国产av
|
||||||
|
好嫩
|
||||||
|
豪乳
|
||||||
|
黑逼
|
||||||
|
后庭
|
||||||
|
后穴
|
||||||
|
虎骑
|
||||||
|
换妻俱乐部
|
||||||
|
黄片
|
||||||
|
几吧
|
||||||
|
鸡吧
|
||||||
|
鸡巴
|
||||||
|
鸡奸
|
||||||
|
妓女
|
||||||
|
奸情
|
||||||
|
叫床
|
||||||
|
脚交
|
||||||
|
精液
|
||||||
|
就去日
|
||||||
|
巨屌
|
||||||
|
菊花洞
|
||||||
|
菊门
|
||||||
|
巨奶
|
||||||
|
巨乳
|
||||||
|
菊穴
|
||||||
|
开苞
|
||||||
|
口爆
|
||||||
|
口活
|
||||||
|
口交
|
||||||
|
口射
|
||||||
|
口淫
|
||||||
|
裤袜
|
||||||
|
狂操
|
||||||
|
狂插
|
||||||
|
浪逼
|
||||||
|
浪妇
|
||||||
|
浪叫
|
||||||
|
浪女
|
||||||
|
狼友
|
||||||
|
聊性
|
||||||
|
凌辱
|
||||||
|
漏乳
|
||||||
|
露b
|
||||||
|
乱交
|
||||||
|
乱伦
|
||||||
|
轮暴
|
||||||
|
轮操
|
||||||
|
轮奸
|
||||||
|
裸陪
|
||||||
|
买春
|
||||||
|
美逼
|
||||||
|
美少妇
|
||||||
|
美乳
|
||||||
|
美腿
|
||||||
|
美穴
|
||||||
|
美幼
|
||||||
|
秘唇
|
||||||
|
迷奸
|
||||||
|
密穴
|
||||||
|
蜜穴
|
||||||
|
蜜液
|
||||||
|
摸奶
|
||||||
|
摸胸
|
||||||
|
母奸
|
||||||
|
奈美
|
||||||
|
奶子
|
||||||
|
男奴
|
||||||
|
内射
|
||||||
|
嫩逼
|
||||||
|
嫩女
|
||||||
|
嫩穴
|
||||||
|
捏弄
|
||||||
|
女优
|
||||||
|
炮友
|
||||||
|
砲友
|
||||||
|
喷精
|
||||||
|
屁眼
|
||||||
|
前凸后翘
|
||||||
|
强jian
|
||||||
|
强暴
|
||||||
|
强奸处女
|
||||||
|
情趣用品
|
||||||
|
情色
|
||||||
|
拳交
|
||||||
|
全裸
|
||||||
|
群交
|
||||||
|
人妻
|
||||||
|
人兽
|
||||||
|
日逼
|
||||||
|
日烂
|
||||||
|
肉棒
|
||||||
|
肉逼
|
||||||
|
肉唇
|
||||||
|
肉洞
|
||||||
|
肉缝
|
||||||
|
肉棍
|
||||||
|
肉茎
|
||||||
|
肉具
|
||||||
|
揉乳
|
||||||
|
肉穴
|
||||||
|
肉欲
|
||||||
|
乳爆
|
||||||
|
乳房
|
||||||
|
乳沟
|
||||||
|
乳交
|
||||||
|
乳头
|
||||||
|
骚逼
|
||||||
|
骚比
|
||||||
|
骚女
|
||||||
|
骚水
|
||||||
|
骚穴
|
||||||
|
色逼
|
||||||
|
色界
|
||||||
|
色猫
|
||||||
|
色盟
|
||||||
|
色情网站
|
||||||
|
色区
|
||||||
|
色色
|
||||||
|
色诱
|
||||||
|
色欲
|
||||||
|
色b
|
||||||
|
少年阿宾
|
||||||
|
射爽
|
||||||
|
射颜
|
||||||
|
食精
|
||||||
|
释欲
|
||||||
|
兽奸
|
||||||
|
兽交
|
||||||
|
手淫
|
||||||
|
兽欲
|
||||||
|
熟妇
|
||||||
|
熟母
|
||||||
|
熟女
|
||||||
|
爽片
|
||||||
|
双臀
|
||||||
|
死逼
|
||||||
|
丝袜
|
||||||
|
丝诱
|
||||||
|
松岛枫
|
||||||
|
酥痒
|
||||||
|
汤加丽
|
||||||
|
套弄
|
||||||
|
体奸
|
||||||
|
体位
|
||||||
|
舔脚
|
||||||
|
舔阴
|
||||||
|
调教
|
||||||
|
偷欢
|
||||||
|
推油
|
||||||
|
脱内裤
|
||||||
|
文做
|
||||||
|
舞女
|
||||||
|
无修正
|
||||||
|
吸精
|
||||||
|
夏川纯
|
||||||
|
相奸
|
||||||
|
小逼
|
||||||
|
校鸡
|
||||||
|
小穴
|
||||||
|
小xue
|
||||||
|
性感妖娆
|
||||||
|
性感诱惑
|
||||||
|
性虎
|
||||||
|
性饥渴
|
||||||
|
性技巧
|
||||||
|
性交
|
||||||
|
性奴
|
||||||
|
性虐
|
||||||
|
性息
|
||||||
|
性欲
|
||||||
|
胸推
|
||||||
|
穴口
|
||||||
|
穴图
|
||||||
|
亚情
|
||||||
|
颜射
|
||||||
|
阳具
|
||||||
|
杨思敏
|
||||||
|
要射了
|
||||||
|
夜勤病栋
|
||||||
|
一本道
|
||||||
|
一夜欢
|
||||||
|
一夜情
|
||||||
|
一ye情
|
||||||
|
阴部
|
||||||
|
淫虫
|
||||||
|
阴唇
|
||||||
|
淫荡
|
||||||
|
阴道
|
||||||
|
淫电影
|
||||||
|
阴阜
|
||||||
|
淫妇
|
||||||
|
淫河
|
||||||
|
阴核
|
||||||
|
阴户
|
||||||
|
淫贱
|
||||||
|
淫叫
|
||||||
|
淫教师
|
||||||
|
阴茎
|
||||||
|
阴精
|
||||||
|
淫浪
|
||||||
|
淫媚
|
||||||
|
淫糜
|
||||||
|
淫魔
|
||||||
|
淫母
|
||||||
|
淫女
|
||||||
|
淫虐
|
||||||
|
淫妻
|
||||||
|
淫情
|
||||||
|
淫色
|
||||||
|
淫声浪语
|
||||||
|
淫兽学园
|
||||||
|
淫书
|
||||||
|
淫术炼金士
|
||||||
|
淫水
|
||||||
|
淫娃
|
||||||
|
淫威
|
||||||
|
淫亵
|
||||||
|
淫样
|
||||||
|
淫液
|
||||||
|
淫照
|
||||||
|
阴b
|
||||||
|
应召
|
||||||
|
幼交
|
||||||
|
欲火
|
||||||
|
欲女
|
||||||
|
玉乳
|
||||||
|
玉穴
|
||||||
|
援交
|
||||||
|
原味内衣
|
||||||
|
援助交际
|
||||||
|
招鸡
|
||||||
|
招妓
|
||||||
|
抓胸
|
||||||
|
自慰
|
||||||
|
作爱
|
||||||
|
a片
|
||||||
|
fuck
|
||||||
|
gay片
|
||||||
|
g点
|
||||||
|
h动画
|
||||||
|
h动漫
|
||||||
|
失身粉
|
||||||
|
淫荡自慰器
|
||||||
1064
Vocabulary/补充词库.txt
Normal file
1064
Vocabulary/补充词库.txt
Normal file
File diff suppressed because it is too large
Load Diff
53308
Vocabulary/零时-Tencent.txt
Normal file
53308
Vocabulary/零时-Tencent.txt
Normal file
File diff suppressed because it is too large
Load Diff
14595
Vocabulary/非法网址.txt
Normal file
14595
Vocabulary/非法网址.txt
Normal file
File diff suppressed because it is too large
Load Diff
96
cmd/server/main.go
Normal file
96
cmd/server/main.go
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sensitive-lexicon/internal/detect"
|
||||||
|
"sensitive-lexicon/internal/lexicon"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Name string `json:"name" validate:"min=5,max=20"`
|
||||||
|
Age int `json:"age" validate:"gte=18"`
|
||||||
|
Enrollment time.Time `json:"enrollment" validate:"before_today"`
|
||||||
|
Graduation time.Time `json:"graduation" validate:"gtfield=Enrollment"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeforeToday 验证日期是否在今天之前
|
||||||
|
func BeforeToday(fl validator.FieldLevel) bool {
|
||||||
|
fieldTime, ok := fl.Field().Interface().(time.Time)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return fieldTime.Before(time.Now())
|
||||||
|
}
|
||||||
|
func main() {
|
||||||
|
lexiconDir := getenv("LEXICON_DIR", "Vocabulary")
|
||||||
|
minNgram := getenvInt("FUZZY_MIN_NGRAM", 2)
|
||||||
|
maxNgram := getenvInt("FUZZY_MAX_NGRAM", 10)
|
||||||
|
maxDistance := getenvInt("FUZZY_MAX_DISTANCE", 1)
|
||||||
|
|
||||||
|
store := lexicon.NewStore()
|
||||||
|
if err := store.LoadFromDir(lexiconDir); err != nil {
|
||||||
|
log.Fatalf("failed to load lexicon: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
service := detect.NewService(store)
|
||||||
|
service.SetFuzzyConfig(detect.FuzzyConfig{MinNgramLen: minNgram, MaxNgramLen: maxNgram, MaxDistance: maxDistance})
|
||||||
|
|
||||||
|
app := fiber.New()
|
||||||
|
app.Get("/health", func(c *fiber.Ctx) error {
|
||||||
|
return c.JSON(fiber.Map{"status": "ok"})
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Post("/detect", func(c *fiber.Ctx) error {
|
||||||
|
var req detect.DetectRequest
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
res := service.Detect(req)
|
||||||
|
return c.JSON(res)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Post("/contains", func(c *fiber.Ctx) error {
|
||||||
|
var req detect.ContainsRequest
|
||||||
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||||
|
}
|
||||||
|
res := service.Contains(req)
|
||||||
|
return c.JSON(res)
|
||||||
|
})
|
||||||
|
|
||||||
|
app.Post("/reload", func(c *fiber.Ctx) error {
|
||||||
|
if err := store.LoadFromDir(lexiconDir); err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||||
|
}
|
||||||
|
stats := store.Stats()
|
||||||
|
return c.JSON(stats)
|
||||||
|
})
|
||||||
|
|
||||||
|
port := getenv("PORT", "8080")
|
||||||
|
addr := ":" + port
|
||||||
|
log.Printf("listening on %s", addr)
|
||||||
|
if err := app.Listen(addr); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getenv(k, def string) string {
|
||||||
|
if v := os.Getenv(k); v != "" {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
|
func getenvInt(k string, def int) int {
|
||||||
|
if v := os.Getenv(k); v != "" {
|
||||||
|
if i, err := strconv.Atoi(v); err == nil {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return def
|
||||||
|
}
|
||||||
30
go.mod
Normal file
30
go.mod
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
module sensitive-lexicon
|
||||||
|
|
||||||
|
go 1.22
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-playground/validator/v10 v10.27.0
|
||||||
|
github.com/gofiber/fiber/v2 v2.52.5
|
||||||
|
github.com/ozeidan/fuzzy-patricia v3.0.0+incompatible
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/google/uuid v1.5.0 // indirect
|
||||||
|
github.com/klauspost/compress v1.17.0 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
|
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||||
|
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||||
|
golang.org/x/crypto v0.33.0 // indirect
|
||||||
|
golang.org/x/net v0.34.0 // indirect
|
||||||
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
|
golang.org/x/text v0.22.0 // indirect
|
||||||
|
)
|
||||||
55
go.sum
Normal file
55
go.sum
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||||
|
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
|
||||||
|
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||||
|
github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
|
||||||
|
github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
|
||||||
|
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||||
|
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||||
|
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
|
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||||
|
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/ozeidan/fuzzy-patricia v3.0.0+incompatible h1:Pl61eMyfJqgY/wytiI4vamqPYribq6d8VxeP1CNyg9M=
|
||||||
|
github.com/ozeidan/fuzzy-patricia v3.0.0+incompatible/go.mod h1:zgvuCcYS7wB7fVCGblsaFFmEe8+aAH13dTYm8FbrpsM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
|
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||||
|
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
||||||
|
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||||
|
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||||
|
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||||
|
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||||
|
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||||
|
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||||
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
144
internal/detect/service.go
Normal file
144
internal/detect/service.go
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
package detect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"sensitive-lexicon/internal/lexicon"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FuzzyConfig struct {
|
||||||
|
MinNgramLen int
|
||||||
|
MaxNgramLen int
|
||||||
|
MaxDistance int
|
||||||
|
}
|
||||||
|
|
||||||
|
type DetectRequest struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
// If true, enable fuzzy detection on n-grams within the text
|
||||||
|
EnableFuzzy bool `json:"enable_fuzzy"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Match struct {
|
||||||
|
Word string `json:"word"`
|
||||||
|
Type string `json:"type"` // substring | fuzzy
|
||||||
|
Distance int `json:"distance,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DetectResponse struct {
|
||||||
|
Hits []Match `json:"hits"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainsRequest struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ContainsResponse struct {
|
||||||
|
Contains bool `json:"contains"`
|
||||||
|
Word string `json:"word,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
store *lexicon.Store
|
||||||
|
fuzzyCfg FuzzyConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewService(store *lexicon.Store) *Service {
|
||||||
|
return &Service{store: store, fuzzyCfg: FuzzyConfig{MinNgramLen: 2, MaxNgramLen: 10, MaxDistance: 1}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) SetFuzzyConfig(cfg FuzzyConfig) {
|
||||||
|
s.fuzzyCfg = cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Detect(req DetectRequest) DetectResponse {
|
||||||
|
text := strings.TrimSpace(req.Text)
|
||||||
|
if text == "" {
|
||||||
|
return DetectResponse{}
|
||||||
|
}
|
||||||
|
|
||||||
|
unique := make(map[string]Match)
|
||||||
|
|
||||||
|
// Substring hits: for each codepoint window from input, find lexicon entries containing it
|
||||||
|
s.store.ForEachSubstringMatch(text, func(word string) bool {
|
||||||
|
unique[word] = Match{Word: word, Type: "substring"}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
if req.EnableFuzzy {
|
||||||
|
for _, token := range generateNgrams(text, s.fuzzyCfg.MinNgramLen, s.fuzzyCfg.MaxNgramLen) {
|
||||||
|
s.store.ForEachFuzzyMatch(token, s.fuzzyCfg.MaxDistance, func(word string, d int) bool {
|
||||||
|
if old, ok := unique[word]; ok {
|
||||||
|
if old.Type == "substring" && d == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unique[word] = Match{Word: word, Type: ternary(d == 0, "substring", "fuzzy"), Distance: d}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res := DetectResponse{Hits: make([]Match, 0, len(unique))}
|
||||||
|
for _, v := range unique {
|
||||||
|
res.Hits = append(res.Hits, v)
|
||||||
|
}
|
||||||
|
sort.Slice(res.Hits, func(i, j int) bool {
|
||||||
|
if res.Hits[i].Type == res.Hits[j].Type {
|
||||||
|
if res.Hits[i].Distance == res.Hits[j].Distance {
|
||||||
|
return res.Hits[i].Word < res.Hits[j].Word
|
||||||
|
}
|
||||||
|
return res.Hits[i].Distance < res.Hits[j].Distance
|
||||||
|
}
|
||||||
|
return res.Hits[i].Type < res.Hits[j].Type
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) Contains(req ContainsRequest) ContainsResponse {
|
||||||
|
ok, w := s.store.HasAnyInText(strings.TrimSpace(req.Text))
|
||||||
|
return ContainsResponse{Contains: ok, Word: w}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ternary[T any](cond bool, a, b T) T {
|
||||||
|
if cond {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateNgrams(text string, minLen, maxLen int) []string {
|
||||||
|
if minLen < 1 {
|
||||||
|
minLen = 1
|
||||||
|
}
|
||||||
|
if maxLen < minLen {
|
||||||
|
maxLen = minLen
|
||||||
|
}
|
||||||
|
// Work on rune boundaries for CJK safety
|
||||||
|
runes := []rune(text)
|
||||||
|
n := len(runes)
|
||||||
|
var out []string
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
for l := minLen; l <= maxLen && i+l <= n; l++ {
|
||||||
|
out = append(out, string(runes[i:i+l]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dedupStrings(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dedupStrings(in []string) []string {
|
||||||
|
seen := make(map[string]struct{}, len(in))
|
||||||
|
out := make([]string, 0, len(in))
|
||||||
|
for _, s := range in {
|
||||||
|
if _, ok := seen[s]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[s] = struct{}{}
|
||||||
|
out = append(out, s)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guard for unused import warning if utf8 not referenced elsewhere
|
||||||
|
var _ = utf8.RuneCountInString
|
||||||
141
internal/lexicon/store.go
Normal file
141
internal/lexicon/store.go
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
package lexicon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ozeidan/fuzzy-patricia/patricia"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Store holds the trie and statistics for the loaded lexicon.
|
||||||
|
type Store struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
trie *patricia.Trie
|
||||||
|
cnt int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStore() *Store {
|
||||||
|
return &Store{trie: patricia.NewTrie()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadFromDir loads all .txt files from dir into the trie.
|
||||||
|
func (s *Store) LoadFromDir(dir string) error {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
newTrie := patricia.NewTrie()
|
||||||
|
count := 0
|
||||||
|
|
||||||
|
walkErr := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if strings.ToLower(filepath.Ext(info.Name())) != ".txt" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
f, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
scanner := bufio.NewScanner(f)
|
||||||
|
// Increase buffer for long lines
|
||||||
|
buf := make([]byte, 0, 1024*64)
|
||||||
|
scanner.Buffer(buf, 1024*1024)
|
||||||
|
for scanner.Scan() {
|
||||||
|
w := strings.TrimSpace(scanner.Text())
|
||||||
|
if w == "" || strings.HasPrefix(w, "#") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newTrie.Insert(patricia.Prefix(w), struct{}{})
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
return scanner.Err()
|
||||||
|
})
|
||||||
|
if walkErr != nil {
|
||||||
|
return walkErr
|
||||||
|
}
|
||||||
|
if count == 0 {
|
||||||
|
return errors.New("no entries loaded")
|
||||||
|
}
|
||||||
|
// Swap in
|
||||||
|
s.trie = newTrie
|
||||||
|
s.cnt = count
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Store) Stats() map[string]interface{} {
|
||||||
|
s.mu.RLock()
|
||||||
|
defer s.mu.RUnlock()
|
||||||
|
return map[string]interface{}{
|
||||||
|
"count": s.cnt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForEachSubstringMatch visits any keys that contain the given substring.
|
||||||
|
// It uses the library's substring search.
|
||||||
|
func (s *Store) ForEachSubstringMatch(query string, visit func(word string) bool) {
|
||||||
|
s.mu.RLock()
|
||||||
|
tr := s.trie
|
||||||
|
s.mu.RUnlock()
|
||||||
|
if tr == nil || query == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// second argument is caseSensitive; we use false by default
|
||||||
|
tr.VisitSubstring(patricia.Prefix(query), false, func(prefix patricia.Prefix, _ patricia.Item) error {
|
||||||
|
// The library does not expose a public stop error in all versions; ignore early stop
|
||||||
|
_ = visit(string(prefix))
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForEachFuzzyMatch visits keys with fuzzy distance within maxDistance to query.
|
||||||
|
func (s *Store) ForEachFuzzyMatch(query string, maxDistance int, visit func(word string, distance int) bool) {
|
||||||
|
s.mu.RLock()
|
||||||
|
tr := s.trie
|
||||||
|
s.mu.RUnlock()
|
||||||
|
if tr == nil || query == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// signature in current lib: VisitFuzzy(prefix, caseSensitive bool, visitor)
|
||||||
|
tr.VisitFuzzy(patricia.Prefix(query), false, func(prefix patricia.Prefix, _ patricia.Item, dist int) error {
|
||||||
|
if dist <= maxDistance {
|
||||||
|
_ = visit(string(prefix), dist)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasAnyInText returns true if any lexicon word is a substring of the given text.
|
||||||
|
// It scans each rune offset and visits prefixes against the trie.
|
||||||
|
func (s *Store) HasAnyInText(text string) (bool, string) {
|
||||||
|
s.mu.RLock()
|
||||||
|
tr := s.trie
|
||||||
|
s.mu.RUnlock()
|
||||||
|
if tr == nil || text == "" {
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
|
runes := []rune(text)
|
||||||
|
n := len(runes)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
suffix := string(runes[i:])
|
||||||
|
foundWord := ""
|
||||||
|
tr.VisitPrefixes(patricia.Prefix(suffix), false, func(prefix patricia.Prefix, _ patricia.Item) error {
|
||||||
|
if foundWord == "" {
|
||||||
|
foundWord = string(prefix)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if foundWord != "" {
|
||||||
|
return true, foundWord
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, ""
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user