Files

200 lines
5.6 KiB
Python
Raw Permalink Normal View History

#!/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()