【问题标题】:Print a list of unique words from a text file after removing punctuation, and find longest word删除标点符号后从文本文件中打印唯一单词列表,并找到最长的单词
【发布时间】:2020-08-28 15:43:12
【问题描述】:

目标是a) 从文本文件中打印唯一单词列表,并b) 找到最长的单词。

  • 我不能在这个挑战中使用导入。

文件处理和主要功能是我想要的,但是需要清理列表。从输出中可以看出,单词与标点符号连接在一起,因此maxLength 显然是不正确的。

with open("doc.txt") as reader, open("unique.txt", "w") as writer:

    unwanted = "[],."
    unique = set(reader.read().split())
    unique = list(unique) 
    unique.sort(key=len)
    regex = [elem.strip(unwanted).split() for elem in unique]
    writer.write(str(regex))
    reader.close()

    maxLength = len(max(regex,key=len ))
    print(maxLength)
    res = [word for word in regex if len(word) == maxLength]
    print(res)



===========

示例:

早在 50 多年前 [7][8][9] 就开创了综合实习年的概念,超过 70% 的学生参加了实习年,这一比例在英国是最高的。[10] em>

【问题讨论】:

标签: python


【解决方案1】:

这是一个解决方案,它使用str.translate() 在我们执行split() 之前丢弃所有坏字符(+ 换行符)。 (通常我们会使用带有re.sub() 的正则表达式,但不允许这样做。)这使得清洁变得单行,这真的很整洁:

bad = "[],.\n"
bad_transtable = str.maketrans(bad, ' ' * len(bad))

# We can directly read and clean the entire output, without a reader object: 
cleaned_input = open('doc.txt').read().translate(bad_transtable)
#with open("doc.txt") as reader:
#    cleaned_input = reader.read().translate(bad_transtable)

# Get list of unique words, in decreasing length
unique_words = sorted(set(cleaned_input.split()), key=lambda w: -len(w))   

with open("unique.txt", "w") as writer:
    for word in unique_words:
        writer.write(f'{word}\n')

max_length = len(unique_words[0])
print ([word for word in unique_words if len(word) == max_length])

注意事项:

  • 由于输入已经 100% 清理和拆分,因此无需在进行时附加到列表/插入到集合中,然后必须稍后再进行一次清理。我们可以直接创建unique_words! (使用set() 只保留唯一性)。在我们处理它的同时,我们不妨使用sorted(..., key=lambda w: -len(w)) 以递减的长度对其进行排序。只需拨打sort() 一次。并且没有迭代附加到列表。
  • 因此我们保证max_length = len(unique_words[0])
  • 这种方法也将比嵌套循环更高效for line in <lines>: for word in line.split(): ...iterative append() to wordlist
  • 不需要明确的writer/reader.open()/.close(),这就是with statement为你做的。 (发生异常时处理 IO 也更优雅。)
  • 您还可以在 writer 循环中合并 max_length 单词的打印。但将它们分开是更简洁的代码。
  • 请注意,当我们 write() 输出行时,我们使用 f-string formatting f'{word}\n' 添加换行符
  • 在 Python 中,我们使用 lower_case_with_underscores 作为变量名,因此 max_length 不是 maxLength。见PEP8
  • 事实上,我们并不需要为作者提供一个 with 语句,如果我们要做的只是用open('doc.txt').read() 一次性吞下它的全部内容。 (这对于大文件是不可扩展的,你必须分块或 n 行读取)。
  • str.maketrans() 是内置的,但如果您的老师反对模块引用,您也可以在绑定字符串上调用它,例如' '.maketrans()
  • str.maketrans() 真的是回到我们只有 95 个可打印 ASCII 字符而不是 Unicode 的日子。 still works on Unicode,但是构建和使用巨大的翻译字典很烦人并且会占用内存,Unicode 上的正则表达式更容易,您可以定义整个字符类。

如果您还不知道的替代解决方案str.translate()

dirty_input = open('doc.txt').read()
cleaned_input = dirty_input
# If you can't use either 're.sub()' or 'str.translate()', have to manually
# str.replace() each bad char one-by-one (or else use a method like str.isalpha())
for bad_char in bad:
    cleaned_input = cleaned_input.replace(bad_char, ' ')

如果你想成为可笑的极简主义者,你可以用列表理解将整个输出文件写在一行中。不要这样做,调试会很糟糕,例如,如果您无法打开/写入/覆盖输出文件,或者出现 IOError,或者 unique_words 不是列表等:

open("unique.txt", "w").writelines([f'{word}\n' for word in unique_words])

【讨论】:

  • 谢谢。很不错。我们还没有看到翻译所以我想知道它是否可以使用替换以类似的方式可行?我喜欢读/写的分离。
  • tymac:在底部添加。是的,str.translate() 非常强大,正则表达式也是如此,解决它们非常烦人......
  • 我注意到在最终列表的末尾还有剩余的数字。它们来自脚注符号[3][5][54][2] 等。由于我们不使用imports,我将如何删除它们?
  • 如何添加排序以按字母顺序排序?我尝试了sorted_unique_words = sorted(unique_words),它在与您的 split() 行结合时不会单独工作。
  • 你是什么意思,sorted(set(cleaned_input.split())) 确实将唯一的单词按字母数字顺序排序,所以数字然后大写然后小写?你想要不区分大小写吗?最后的数字?等等。所有这些都有重复的问题,请搜索它们或发布一个新问题。
【解决方案2】:

这是另一个没有任何功能的解决方案。

bad = '`~@#$%^&*()-_=+[]{}\|;\':\".>?<,/?'

clean = ' '
for i in a:
    if i not in bad:
        clean += i
    else:
        clean += ' '

cleans = [i for i in clean.split(' ') if len(i)]

clean_uniq = list(set(cleans))

clean_uniq.sort(key=len)

print(clean_uniq)
print(len(clean_uniq[-1]))

【讨论】:

    【解决方案3】:

    这里有一个解决方案。诀窍是使用python str 方法.isalpha() 过滤非字母数字。

    with open("unique.txt", "w") as writer:
        with open("doc.txt") as reader:
            cleaned_words = []
            for line in reader.readlines():
                for word in line.split():
                    cleaned_word = ''.join([c for c in word if c.isalpha()])
                    if len(cleaned_word):
                        cleaned_words.append(cleaned_word)
    
            # print unique words
            unique_words = set(cleaned_words)
            print(unique_words)
    
            # write words to file? depends what you need here
            for word in unique_words:
                writer.write(str(word))
                writer.write('\n')
    
            # print length of longest
            print(len(sorted(unique_words, key=len, reverse=True)[0]))
    

    【讨论】:

    • 谢谢。 p.s.好奇,有没有不用isalpha的方法?
    • 你能把作者也包括在你的答案中吗?你说的是美学。谢谢。
    • OP 的代码还会打印所有(唯一)最长长度的单词,而不仅仅是它们的实际长度。
    • 我已经添加回作者中(我认为@smci 的示例只有在相关上下文中读取和写入的代码更加简洁)。请适应您希望输出格式的方式。下面smci的解决方案也使用.translate()而不是.isalpha()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-01-19
    • 2020-09-18
    • 1970-01-01
    • 2019-04-26
    • 2013-04-28
    • 1970-01-01
    • 2020-02-26
    相关资源
    最近更新 更多