str.split()返回一个AttributeError:'NoneType'对象没有属性'split'

2024-06-16 11:17:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我很难在上拆分字符串\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_文本文件中出现的所有“\n”,因此这不是问题所在。字符串不能通过一个字符传递到标记器/标记器中,因为它根据长字符串确定str是单词。它对前100万个字符有效,但在10万个字符时失败,这一事实告诉我,这可能是一千万次中的一次。我已经寻找了几个小时的解决方案,但找不到任何有助于解决这个问题的方法。我可能会将字符串分为100万个块传递,但在可能有解决方案的情况下,丢失那么多数据是错误的

任何帮助都将不胜感激

@Ivanlima先生谢谢你修改了我帖子的语法

@Karl Knechtel advise在评论中为我的问题找到了解决办法。谢谢大家!

对于那些感兴趣的人,以下是最终有效的完整代码:

%%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

Tags: the字符串textin标记forlowertemp
1条回答
网友
1楼 · 发布于 2024-06-16 11:17:20

我是mecab-python3的开发者

我想你可能已经就此给我发了邮件,但请不要传递MeCab 1M字符串。它是在假设输入是一个句子的情况下发展起来的。它很健壮,并且可以处理更长的字符串——例如,你在处理段落时不会遇到问题——但你基本上是在毫无益处地进入未经测试的领域

在将输入文本传递给MeCab之前,将其拆分为段落或句子

此外,关于这一点:

I could potentially pass the string in 1M chunks but it feels wrong losing that much data when there might be a solution somewhere.

传递较短的字符串不会丢失任何数据。我不知道你指的是什么

相关问题 更多 >