BangStarlight / tools /sentence.py
Mahiruoshi's picture
Update tools/sentence.py
ea40339 verified
raw
history blame
14.8 kB
import re, os
from ebooklib import epub
import PyPDF2
from PyPDF2 import PdfReader
from bs4 import BeautifulSoup
import jieba
import romajitable
def is_japanese(string):
for ch in string:
if ord(ch) > 0x3040 and ord(ch) < 0x30FF:
return True
return False
def is_chinese(string):
for ch in string:
if '\u4e00' <= ch <= '\u9fff':
return True
return False
def is_single_language(sentence):
# 检查句子是否为单一语言
contains_chinese = re.search(r'[\u4e00-\u9fff]', sentence) is not None
contains_japanese = re.search(r'[\u3040-\u30ff\u31f0-\u31ff]', sentence) is not None
contains_english = re.search(r'[a-zA-Z]', sentence) is not None
language_count = sum([contains_chinese, contains_japanese, contains_english])
return language_count == 1
def merge_scattered_parts(sentences):
"""合并零散的部分到相邻的句子中,并确保单一语言性"""
merged_sentences = []
buffer_sentence = ""
for sentence in sentences:
# 检查是否是单一语言或者太短(可能是标点或单个词)
if is_single_language(sentence) and len(sentence) > 1:
# 如果缓冲区有内容,先将缓冲区的内容添加到列表
if buffer_sentence:
merged_sentences.append(buffer_sentence)
buffer_sentence = ""
merged_sentences.append(sentence)
else:
# 如果是零散的部分,将其添加到缓冲区
buffer_sentence += sentence
# 确保最后的缓冲区内容被添加
if buffer_sentence:
merged_sentences.append(buffer_sentence)
return merged_sentences
def is_only_punctuation(s):
"""检查字符串是否只包含标点符号"""
# 此处列出中文、日文、英文常见标点符号
punctuation_pattern = re.compile(r'^[\s。*;,:“”()、!?《》\u3000\.,;:"\'?!()]+$')
return punctuation_pattern.match(s) is not None
def split_mixed_language(sentence):
# 分割混合语言句子
# 逐字符检查,分割不同语言部分
sub_sentences = []
current_language = None
current_part = ""
for char in sentence:
if re.match(r'[\u4e00-\u9fff]', char): # Chinese character
if current_language != 'chinese':
if current_part:
sub_sentences.append(current_part)
current_part = char
current_language = 'chinese'
else:
current_part += char
elif re.match(r'[\u3040-\u30ff\u31f0-\u31ff]', char): # Japanese character
if current_language != 'japanese':
if current_part:
sub_sentences.append(current_part)
current_part = char
current_language = 'japanese'
else:
current_part += char
elif re.match(r'[a-zA-Z]', char): # English character
if current_language != 'english':
if current_part:
sub_sentences.append(current_part)
current_part = char
current_language = 'english'
else:
current_part += char
else:
current_part += char # For punctuation and other characters
if current_part:
sub_sentences.append(current_part)
return sub_sentences
def replace_quotes(text):
# 替换中文、日文引号为英文引号
text = re.sub(r'[“”‘’『』「」()()]', '"', text)
return text
def remove_numeric_annotations(text):
# 定义用于匹配数字注释的正则表达式
# 包括 “”、【】和〔〕包裹的数字
pattern = r'“\d+”|【\d+】|〔\d+〕'
# 使用正则表达式替换掉这些注释
cleaned_text = re.sub(pattern, '', text)
cleaned_text = re.sub('「', '', cleaned_text)
cleaned_text = re.sub('」', '', cleaned_text)
return cleaned_text
def merge_adjacent_japanese(sentences):
"""合并相邻且都只包含日语的句子"""
merged_sentences = []
i = 0
while i < len(sentences):
current_sentence = sentences[i]
if i + 1 < len(sentences) and is_japanese(current_sentence) and is_japanese(sentences[i + 1]):
# 当前句子和下一句都是日语,合并它们
while i + 1 < len(sentences) and is_japanese(sentences[i + 1]):
current_sentence += sentences[i + 1]
i += 1
merged_sentences.append(current_sentence)
i += 1
return merged_sentences
def extrac(text):
text = replace_quotes(remove_numeric_annotations(text)) # 替换引号
text = re.sub("<[^>]*>", "", text) # 移除 HTML 标签
# 使用换行符和标点符号进行初步分割,确保标点符号保留在句子末尾
preliminary_sentences = re.split(r'(?<=[\n。;!?\.\?!。])', text)
final_sentences = []
for piece in preliminary_sentences:
if is_single_language(piece):
if len(piece) > 15:
sub_sentences = split_long_sentences(piece)
final_sentences.extend(sub_sentences)
final_sentences.append(piece)
else:
sub_sentences = split_mixed_language(piece)
final_sentences.extend(sub_sentences)
# 移除双引号和空白字符
return [s.replace('"', '').strip() for s in final_sentences if s]
def is_mixed_language(sentence):
contains_chinese = re.search(r'[\u4e00-\u9fff]', sentence) is not None
contains_japanese = re.search(r'[\u3040-\u30ff\u31f0-\u31ff]', sentence) is not None
contains_english = re.search(r'[a-zA-Z]', sentence) is not None
languages_count = sum([contains_chinese, contains_japanese, contains_english])
return languages_count > 1
def split_mixed_language(sentence):
# 分割混合语言句子
sub_sentences = re.split(r'(?<=[。!?\.\?!])(?=")|(?<=")(?=[\u4e00-\u9fff\u3040-\u30ff\u31f0-\u31ff]|[a-zA-Z])', sentence)
return [s.strip() for s in sub_sentences if s.strip()]
def seconds_to_ass_time(seconds):
"""将秒数转换为ASS时间格式"""
hours = int(seconds / 3600)
minutes = int((seconds % 3600) / 60)
seconds = int(seconds) % 60
milliseconds = int((seconds - int(seconds)) * 1000)
return "{:01d}:{:02d}:{:02d}.{:02d}".format(hours, minutes, seconds, int(milliseconds / 10))
def extract_text_from_epub(file_path):
book = epub.read_epub(file_path)
content = []
for item in book.items:
if isinstance(item, epub.EpubHtml):
soup = BeautifulSoup(item.content, 'html.parser')
content.append(soup.get_text())
return '\n'.join(content)
def extract_text_from_pdf(file_path):
with open(file_path, 'rb') as file:
reader = PdfReader(file)
content = [page.extract_text() for page in reader.pages]
return '\n'.join(content)
def remove_annotations(text):
# 移除方括号、尖括号和中文方括号中的内容
text = re.sub(r'\[.*?\]', '', text)
text = re.sub(r'\<.*?\>', '', text)
text = re.sub(r'&#8203;``【oaicite:1】``&#8203;', '', text)
return text
def extract_text_from_file(inputFile):
file_extension = os.path.splitext(inputFile)[1].lower()
if file_extension == ".epub":
return extract_text_from_epub(inputFile)
elif file_extension == ".pdf":
return extract_text_from_pdf(inputFile)
elif file_extension == ".txt":
with open(inputFile, 'r', encoding='utf-8') as f:
return f.read()
else:
raise ValueError(f"Unsupported file format: {file_extension}")
def split_by_punctuation(sentence):
"""按照中文次级标点符号分割句子"""
# 常见的中文次级分隔符号:逗号、分号等
parts = re.split(r'([,,;;…、『』「」])', sentence)
# 将标点符号与前面的词语合并,避免单独标点符号成为一个部分
merged_parts = []
for part in parts:
if part and not part in ',,;;':
merged_parts.append(part)
elif merged_parts:
merged_parts[-1] += part
return merged_parts
def split_long_sentences(sentence, max_length=30):
"""如果中文句子太长,先按标点分割,必要时使用jieba进行分词并分割"""
preliminary_parts = split_by_punctuation(sentence)
new_sentences = []
for part in preliminary_parts:
new_sentences.append(part)
return new_sentences
def extract_and_convert(text):
# 使用正则表达式找出所有英文单词
english_parts = re.findall(r'\b[A-Za-z]+\b', text) # \b为单词边界标识
# 对每个英文单词进行片假名转换
kana_parts = ['\n{}\n'.format(romajitable.to_kana(word).katakana) for word in english_parts]
# 替换原文本中的英文部分
for eng, kana in zip(english_parts, kana_parts):
text = text.replace(eng, kana, 1) # 限制每次只替换一个实例
return text
if __name__ == "__main__":
text = ",如“520”,【23】和〔83〕等。.我亲爱的读者,你也许在某一刻会遇上这样的情形,不禁对那著名哲学句子“那内在的就是那外在的,那外在的就是那内在的”“3”的正确性有了或多或少的怀疑。也许你自己就怀着某种秘密,对之你有着这样一种感觉:因为这秘密在它所具有的喜悦或者痛楚对你来说是太亲切了,以至于你不愿意让他人来和你共享它。也许你的生活使得你和一些人有所接触,对于他们你有着某种预感,隐约感觉到如此的某些事情是可能的,尽管你并不一定能够通过权力或者诱惑来揭示这隐秘。也许你感受到的这些情形并不对你和你的生活发生作用,然而你对这种怀疑却不陌生;它时而在你的思绪中像一种匆匆的形影飘忽而过。这样的一种怀疑来而又去,没有人知道它从哪里来或者它到什么地方去“4”。就我自己而言,我一直对哲学的这一点怀有一种异端的想法,并且因此也尽可能地习惯于自己去深思和考究;我从在这方面与我有同感的作家们那里听取了指导,简言之,我尽了我的努力来弥补那些哲学文本们所遗留下的匮乏。渐渐地,听觉对于我来说倒成了最亲密的感觉功能;因为,正如声音是那相对外在之物而言是无法比较的内在性的揭示,于是耳朵就是用来使这内在性得以被人领会的工具,而听觉就是用来获取这内在性的感觉功能的。每当我在我所见和所听之间发现一个矛盾时,我就觉得我的怀疑得到了强化,而我的观察愿望得到了放大。一个听忏悔的神父与忏悔者之间有窗格子隔开,这神父不看,他只是听。听着听着,他渐渐构想出一个与此相应的外在;这就是说,他不会进入矛盾。相反,在你同时看和听的时候则不同,你看着的是你和言述者之间的一道窗格子。就结果而言,我为在这方面进行观察而做出的努力是非常不同的。有时候我是幸运的,有时候则不,而想要在这些道路上赢得一些战利品,幸运总是一个必须被考虑进去的因素。然而我却从来没有失去继续进行我的调查研究的愿望。如果我真的在什么时候几乎对我的坚定感到了懊悔,那么一种意外幸运也就在这样的时候为我的努力进行了加冕。于是这就是一种意外的幸运,它以一种最奇怪的方式使得我拥有了这些文稿,因而我荣幸地在此向阅读着的关注者们展示这些文稿。在这些文稿中,我得到机会去审视进两个人的生活,这强化了我关于“那外在的不是那内在的”的怀疑。尤其是他们中的一个有着这样的情形。他的外在完全与他的内在相矛盾。而他们中另一个的情形在一定的程度上也是如此,只要他在一种较为无足轻重的外在之下隐藏起了一种更为意义重大的内在,那么他就是处在这样的矛盾中。也许,考虑到顺序,我最好还是先讲述一下,我是怎样获得这些文稿的。现在算来,差不多是在七年前,我在城里的一个旧货商家那里留意到一张文书写字柜“5”,一见之下,它就吸引了我的注意力。它不是出自现代的工艺,很陈旧,但它还是吸引住了我。要解说这一印象的依据,对于我来说是不可能的,但是大多数人在他们的生命中肯定也曾经历过类似的情形。我每天的路径使我经过那旧货商和他的柜桌,在任何一天经过那里时我都从不曾放过时机盯着它看。渐渐地,这个文书写字柜在我心中有了它的故事;看着它,对于我来说成了一种必然,到最后,即使是在我有必要走另一条路的时候,我也毫不犹豫地为它的缘故而绕一段远路。由于我总这样看它,它在我心中也渐渐唤醒一种想要拥有它的愿望。其实我完全能感觉到,这是一种奇怪的愿望,既然我并不需要这家具;对于我来说,买下它就是一种浪费。正如我们所知,愿望有着一种非常诡辩性的说服力。我去了那旧货商家,推说是询问一些别的东西,在我要离开的时候,我漫不经心地就那张文书写字柜问了一个非常低的价钱。我想着,那旧货商人可能会抬价。如果是那个价,那我就占了便宜。不管怎么说,我这样做不是为了钱的缘故,而是为了要在良心上说得过去。但没有成功,那旧货商人有着一种非同寻常的坚定。又是很长一段时间,我每天都去那里,然后以一种钟情着迷的目光看着这文书写字柜。你必须下决心,我寻思着,试想一下,如果它被卖掉了,那就太晚了;哪怕你终于又找到它,你也永远得不到对它的这种印象了。在我走进旧货商家的时候,我的心狂跳着。买下了它,付了钱。这是最后一次了,我想着,你这么浪费;对了,你买下它,这恰恰是一种幸运,因为你这么老是看着它,你就该想着你曾是多么浪费,以这个文书写字柜为起点,你生活中该有一个新的段落开始了。啊,愿望有着一种非常诡辩性的说服力,那些良好的意图总是现成地摆在那里。另外参看阿德勒尔(A.P.Adler)的《对黑格尔的客观逻辑的普及讲演》。“5”[文书写字柜(Secretair)] 法国式柜子,有着许多小的、有时是隐秘的抽屉用于保存文件,并且有一块垂直翻板可以拴出来并且当写字台用。"
#print("原文本:", text)
print("处理后的文本:", extrac(text))