python - str.split() 返回一个 AttributeError: 'NoneType' 对象没有属性 'split'
问题描述
我很难在 \n 上拆分字符串。我正在将一个约 138M 长的日语字符串传递到一个标记器/单词标记器中,并且我得到了“AttributeError:'NoneType'对象没有属性'split'”错误。
分词器的名称是 MeCab,它的作用是获取一个字符串,在其中找到单词,然后返回一个具有单词特征(名词、粒子、阅读等)的字符串。分词器在字符串中标记的词是用“\n”分割,所以我想用新行把它分割成一个列表。
字符串的前 25 个字符:
str_text[:25]
输出:
'このページは以下にある削除依頼の議論を保存したもの'
当我使用下面的代码拆分前 100 万个字符时,我没有错误,但是当我将其扩展到 1000 万个时,我得到了上面提到的错误。
前 25 个字符的代码和输出:
import MeCab
#opening the file containing the long string with Japanese text
file = open('output_text.txt')
str_text = file.read()
#passing string into the MeCab tokenizer/tagger and splitting the long string into a list based on
tagger = MeCab.Tagger()
words = tagger.parse(str_text[:25]).split('\n')[:-2] #last two entries are just some tagger info
for word in words:
temp_str = word.split('\t')
print(temp_str)
输出(第一个元素是单词,第二个元素包含有关单词的信息):
['この', '連体詞,*,*,*,*,*,この,コノ,コノ']
['ページ', '名詞,一般,*,*,*,*,ページ,ページ,ページ']
['は', '助詞,係助詞,*,*,*,*,は,ハ,ワ']
['以下', '名詞,非自立,副詞可能,*,*,*,以下,イカ,イカ']
['に', '助詞,格助詞,一般,*,*,*,に,ニ,ニ']
['ある', '動詞,自立,*,*,五段・ラ行,基本形,ある,アル,アル']
['削除', '名詞,サ変接続,*,*,*,*,削除,サクジョ,サクジョ']
['依頼', '名詞,サ変接続,*,*,*,*,依頼,イライ,イライ']
['の', '助詞,連体化,*,*,*,*,の,ノ,ノ']
['議論', '名詞,サ変接続,*,*,*,*,議論,ギロン,ギロン']
['を', '助詞,格助詞,一般,*,*,*,を,ヲ,ヲ']
['保存', '名詞,サ変接続,*,*,*,*,保存,ホゾン,ホゾン']
['し', '動詞,自立,*,*,サ変・スル,連用形,する,シ,シ']
['た', '助動詞,*,*,*,特殊・タ,基本形,た,タ,タ']
['もの', '名詞,非自立,一般,*,*,*,もの,モノ,モノ']
我替换了 str_text 文件中出现的所有“\n”,所以这不是问题。字符串不能真正通过一个字符传递到标记器/标记器,因为它根据长字符串确定 str 是一个单词。它适用于前 1M 字符但在 10M 时失败的事实告诉我,这个我是千万分之一。我已经寻找了几个小时的解决方案,但找不到任何可以帮助解决此问题的方法。我可能会以 1M 块的形式传递字符串,但是当某处可能有解决方案时,丢失这么多数据感觉不对。
任何帮助将不胜感激。
@mrivanlima 感谢您修正我帖子的语法
@Karl Knechtel 在评论中建议解决了我的问题。谢谢!
对于那些感兴趣的人,下面是最终工作的完整代码:
%%time
#load the txt file with Japanese characters:
file = open('output_text.txt')
str_text = file.read()
#boundries for the text blocks used in the below for loop
lower = 0
upper = 100000
#dictionary for words and kanji characters
counts_words = dict()
counts_kanji = dict()
word_counter = 0
#tokenizer/tagger
tagger = MeCab.Tagger()
#splits strings into a list, used for words that have more than one character to get individual characters
def splitter(word):
return list(word)
#break condition for the loop
condition = 'no'
while True:
if condition == 'yes':
break
#this is for the last block of 100k increments
elif lower > 133400001:
#initiate break condition
condition = 'yes'
words = tagger.parse(str_text[lower:]).split('\n')[:-2]
print('Last block, chief!',lower,':',upper)
lower+=100000
upper+=100000
for word in words:
temp_str = word.split('\t')
word_counter+=1
counts_words[temp_str[0]+' '+temp_str[1]] = counts_words.get(temp_str[0]+' '+temp_str[1], 0) + 1
if len(temp_str[0])>1:
for i in splitter(temp_str[0]):
counts_kanji[i] = counts_kanji.get(i, 0) + 1
break
else:
counts_kanji[temp_str[0]] = counts_kanji.get(temp_str[0], 0) + 1
break
else:
#pass string 100k long string block into a tokenizer/tagger
words = tagger.parse(str_text[lower:upper]).split('\n')[:-2]
#increment the lower and upper boundries of the str blocks
lower+=100000
upper+=100000
#iterate through each word parsed by the tokenizer
for word in words:
temp_str = word.split('\t') #split each word data by tab, [word, info]
word_counter+=1 #count number of words
#check if the entry exists in the words dict, either add or increment the counts
counts_words[temp_str[0]+' '+temp_str[1]] = counts_words.get(temp_str[0]+' '+temp_str[1], 0) + 1
#check if the word has more than one character, if yes split it and add each character to the kanji dict
if len(temp_str[0])>1:
for i in splitter(temp_str[0]):
#check if the entry exists in the words dict, either add or increment the counts
counts_kanji[i] = counts_kanji.get(i, 0) + 1
else:
counts_kanji[temp_str[0]] = counts_kanji.get(temp_str[0], 0) + 1
输出:
Last block, chief! 133500000 : 133600000
CPU times: user 3min 7s, sys: 2.83 s, total: 3min 10s
Wall time: 3min 10s
解决方案
我是 mecab-python3 的开发者。
我想你可能已经给我发了邮件,但是请不要传递 MeCab 1M 字符串。它是在假设输入是单个句子的情况下开发的。它很健壮,而且它可以处理更长的字符串——例如,你不会对段落有任何问题——但你基本上会进入未经测试的领域而没有任何好处。
在将输入文本传递给 MeCab 之前,将其拆分为段落或句子。
另外,关于这个:
我可能会以 1M 块的形式传递字符串,但是当某处可能有解决方案时,丢失这么多数据感觉不对。
传递较短的字符串不会丢失任何数据。我不确定你在这里指的是什么。
推荐阅读
- java - 如果在底部导航栏中选择了其他项目,如何删除 floatingActionButton 替换片段
- c++ - 带有 bad_alloc 的虚拟类的多态性
- node.js - 将 .npmrc 文件添加到 Angular 项目
- docker - “绑定:地址已在使用中”,同时通过监听容器端口的 systemd 套接字启动 docker 容器
- string - 期望 - 如何找出变量是否包含字符串
- python - AWS lambda 函数中的 Numpy
- node.js - 云功能 - 如何编写参考文档并修复 NaN
- kotlin - 简化此代码示例以减少行数
- java - SourceDataLine (usb midi) 按键记录会降低实时播放速度
- keyboard - 如何在 AutoHotkey 中获取当前的键盘布局(语言设置)