Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
200 lines
5.6 KiB
Python
200 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
信息提取脚本 - 从文本中提取结构化信息
|
|
|
|
提取内容:
|
|
- 数字
|
|
- 日期
|
|
- 百分比
|
|
- 金额
|
|
- 邮箱
|
|
- URL
|
|
- 电话号码
|
|
|
|
用法:
|
|
echo "2024年销售额为100万元,同比增长15%" | python extract_info.py
|
|
|
|
# 指定提取类型
|
|
echo "联系我: test@example.com 或 13800138000" | python extract_info.py --types email,phone
|
|
"""
|
|
|
|
import sys
|
|
import json
|
|
import argparse
|
|
import re
|
|
|
|
|
|
def extract_numbers(text: str) -> list:
|
|
"""提取数字"""
|
|
# 匹配整数和小数
|
|
pattern = r'-?\d+(?:\.\d+)?'
|
|
numbers = re.findall(pattern, text)
|
|
# 转换为数值
|
|
result = []
|
|
for n in numbers:
|
|
try:
|
|
if '.' in n:
|
|
result.append(float(n))
|
|
else:
|
|
result.append(int(n))
|
|
except ValueError:
|
|
result.append(n)
|
|
return result
|
|
|
|
|
|
def extract_dates(text: str) -> list:
|
|
"""提取日期"""
|
|
patterns = [
|
|
r'\d{4}[-/年]\d{1,2}[-/月]\d{1,2}[日]?', # 2024-01-01 或 2024年1月1日
|
|
r'\d{4}[-/年]\d{1,2}[月]?', # 2024-01 或 2024年1月
|
|
r'\d{4}年', # 2024年
|
|
r'\d{1,2}[-/月]\d{1,2}[日]?', # 01-01 或 1月1日
|
|
]
|
|
|
|
dates = []
|
|
for pattern in patterns:
|
|
matches = re.findall(pattern, text)
|
|
dates.extend(matches)
|
|
|
|
return list(set(dates))
|
|
|
|
|
|
def extract_percentages(text: str) -> list:
|
|
"""提取百分比"""
|
|
pattern = r'-?\d+(?:\.\d+)?%'
|
|
return re.findall(pattern, text)
|
|
|
|
|
|
def extract_amounts(text: str) -> list:
|
|
"""提取金额"""
|
|
patterns = [
|
|
r'[¥$€£]\s*\d+(?:,\d{3})*(?:\.\d+)?', # ¥100.00
|
|
r'\d+(?:,\d{3})*(?:\.\d+)?\s*[元万亿美金]', # 100万元
|
|
r'\d+(?:\.\d+)?[百千万亿]+[元]?', # 100万
|
|
]
|
|
|
|
amounts = []
|
|
for pattern in patterns:
|
|
matches = re.findall(pattern, text)
|
|
amounts.extend(matches)
|
|
|
|
return list(set(amounts))
|
|
|
|
|
|
def extract_emails(text: str) -> list:
|
|
"""提取邮箱"""
|
|
pattern = r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}'
|
|
return re.findall(pattern, text)
|
|
|
|
|
|
def extract_urls(text: str) -> list:
|
|
"""提取 URL"""
|
|
pattern = r'https?://[^\s<>"{}|\\^`\[\]]+'
|
|
return re.findall(pattern, text)
|
|
|
|
|
|
def extract_phones(text: str) -> list:
|
|
"""提取电话号码"""
|
|
patterns = [
|
|
r'1[3-9]\d{9}', # 手机号
|
|
r'\d{3,4}[-\s]?\d{7,8}', # 固话
|
|
r'\+\d{1,3}[-\s]?\d{10,12}', # 国际号码
|
|
]
|
|
|
|
phones = []
|
|
for pattern in patterns:
|
|
matches = re.findall(pattern, text)
|
|
phones.extend(matches)
|
|
|
|
return list(set(phones))
|
|
|
|
|
|
def extract_keywords(text: str, min_len: int = 2) -> list:
|
|
"""提取关键词(中文和英文)"""
|
|
# 中文关键词
|
|
chinese_pattern = r'[\u4e00-\u9fa5]{2,}'
|
|
chinese_words = re.findall(chinese_pattern, text)
|
|
|
|
# 英文关键词
|
|
english_pattern = r'[a-zA-Z]{3,}'
|
|
english_words = re.findall(english_pattern, text)
|
|
|
|
# 统计词频
|
|
from collections import Counter
|
|
words = chinese_words + [w.lower() for w in english_words]
|
|
|
|
# 过滤停用词
|
|
stopwords = {'的', '是', '在', '了', '和', '与', '或', '为', '有', '这', '那', '等',
|
|
'the', 'is', 'are', 'was', 'were', 'and', 'or', 'for', 'with', 'this'}
|
|
words = [w for w in words if w not in stopwords and len(w) >= min_len]
|
|
|
|
word_freq = Counter(words)
|
|
return [{"word": w, "count": c} for w, c in word_freq.most_common(20)]
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="信息提取工具")
|
|
parser.add_argument("--types", "-t",
|
|
help="要提取的类型,逗号分隔 (numbers,dates,percentages,amounts,emails,urls,phones,keywords)")
|
|
parser.add_argument("--pretty", "-p", action="store_true", help="格式化输出")
|
|
args = parser.parse_args()
|
|
|
|
# 读取输入
|
|
try:
|
|
text = sys.stdin.read()
|
|
if not text.strip():
|
|
print(json.dumps({"error": "空输入"}))
|
|
return
|
|
except Exception as e:
|
|
print(json.dumps({"error": f"读取错误: {str(e)}"}))
|
|
return
|
|
|
|
# 确定要提取的类型
|
|
all_types = ["numbers", "dates", "percentages", "amounts", "emails", "urls", "phones", "keywords"]
|
|
if args.types:
|
|
extract_types = [t.strip().lower() for t in args.types.split(",")]
|
|
else:
|
|
extract_types = all_types
|
|
|
|
# 提取信息
|
|
result = {
|
|
"success": True,
|
|
"text_length": len(text),
|
|
"extracted": {}
|
|
}
|
|
|
|
extractors = {
|
|
"numbers": extract_numbers,
|
|
"dates": extract_dates,
|
|
"percentages": extract_percentages,
|
|
"amounts": extract_amounts,
|
|
"emails": extract_emails,
|
|
"urls": extract_urls,
|
|
"phones": extract_phones,
|
|
"keywords": extract_keywords,
|
|
}
|
|
|
|
for ext_type in extract_types:
|
|
if ext_type in extractors:
|
|
try:
|
|
extracted = extractors[ext_type](text)
|
|
if extracted:
|
|
result["extracted"][ext_type] = extracted
|
|
except Exception as e:
|
|
result["extracted"][ext_type] = {"error": str(e)}
|
|
|
|
# 统计
|
|
result["summary"] = {
|
|
"total_extractions": sum(len(v) if isinstance(v, list) else 0
|
|
for v in result["extracted"].values()),
|
|
"types_found": list(result["extracted"].keys())
|
|
}
|
|
|
|
# 输出
|
|
indent = 2 if args.pretty else None
|
|
print(json.dumps(result, ensure_ascii=False, indent=indent))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|