【问题标题】:How to get the original sentence from a text file by knowing an offset of a word in python?如何通过知道python中单词的偏移量从文本文件中获取原始句子?
【发布时间】:2021-10-13 13:23:45
【问题描述】:

我是 python 新手,我想知道是否有一种有效的方法可以通过知道单词的偏移量来从文本文件中找到原始句子。假设我有一个这样的 test.txt 文件:

test.txt

Ceci est une wheat phrase corn.
Ceci est une deuxième phrase barley.
This is the third wheat word.

假设我知道“小麦”这个词的偏移量是 [13,18]。

我的代码如下所示:

import nltk
from nltk.tokenize import word_tokenize

with open("test.txt") as f:
    list_phrase = f.readlines()
    f.seek(0)
    contents = f.read()
    for index, phrase in enumerate(list_phrase):
        j = word_tokenize(phrase)
        if contents[13:18] in j:
            print(list_phrase[index])

我的代码的输出将打印两个句子,即(“Ceci est une wheat phrase corn.”和“This is the third wheat word.”)

如何通过知道单词的偏移量来准确检测单词的真实短语?

请注意,我考虑的偏移量在许多句子(本例中为 2 个句子)之间继续存在。例如,“barley”这个词的偏移量应该是[61,67]。

上面打印的期望输出应该是:

Ceci est une wheat phrase corn.

我们知道它的偏移量是 [13,18]。

对此的任何帮助将不胜感激。非常感谢!

【问题讨论】:

  • 您的代码看起来差不多。如果“小麦”包含在多个短语中,您希望发生什么?您要打印所有匹配项,还是只打印第一个匹配项?
  • 你是如何得到偏移量的?可以同时收线吗?
  • @ti7--我从另一个代码中得到它。假设在这里我知道单词的偏移量并想从文本中找到它的原始句子(由许多短语组成)
  • @TimRoberts——如果小麦包含在许多短语中。我只想打印一个与其在整个文本中的偏移量匹配的短语。

标签: python nltk text-files offset


【解决方案1】:

如果您正在寻找原始速度,那么标准库可能是最好的方法。

# Generate a large text file with 10,000,001 lines.
with open('very-big.txt', 'w') as file:
    for _ in range(10000000):
        file.write("All work and no play makes Jack a dull boy.\n")
    file.write("Finally we get to the line containing the word 'wheat'.\n")

鉴于我们正在寻找的行中的search_word 及其offset,我们可以计算limit 以进行字符串比较。

search_word = 'wheat'
offset = 48
limit = offset + len(search_word)

最简单的方法是遍历枚举的文本行,并对每一行进行字符串比较。

with open('very-big.txt', 'r') as file:
    for line, text in enumerate(file, start=1):
        if (text[offset:limit] == search_word):
            print(f'Line {line}: "{text.strip()}"')

此解决方案的运行时间是 155 ms 在 2012 Mac mini(2.3GHz i7 CPU)上。这对于处理 10,000,001 行来说似乎相当快,但可以通过在尝试字符串比较之前检查文本的长度来改进它。

with open('very-big.txt', 'r') as file:
    for line, text in enumerate(file, start=1):
        if (len(text) >= limit) and (text[offset:limit] == search_word):
            print(f'Line {line}: "{text.strip()}"')

改进解决方案的运行时间是71 ms 在同一台计算机上。这是一个显着的改进,但当然里程会因文本文件而异。

生成的输出:

Line 10000001: "Finally we get to the line containing the word 'wheat'."

编辑:包括文件偏移信息

with open('very-big.txt', 'r') as file:
    file_offset = 0
    for line, text in enumerate(file, start=1):
        line_length = len(text)
        if line_length >= limit and (text[offset:limit] == search_word):
            print(f'[{file_offset + offset}, {file_offset + limit}] Line {line}: "{text.strip()}"')
        file_offset += line_length

样本输出:

[430000048, 430000053] Line 10000001: "Finally we get to the line containing the word 'wheat'."

Encore une fois

此代码检查文本的已知偏移量是否介于当前行开头和行尾的偏移值之间。在偏移处找到的文本也得到了验证。

long_string = """Ceci est une wheat phrase corn.
Ceci est une deuxième phrase barley.
This is the third wheat word.
"""

import io

search_word = 'barley'
known_offset = 61
limit = known_offset + len(search_word)

# Use the multi-line string defined above as file input
with io.StringIO(long_string) as file:
    file_offset = 0
    for line, text in enumerate(file, start=1):
        line_length = len(text)
        if file_offset < known_offset < (file_offset + line_length) \
        and (text[(known_offset-file_offset):(limit-file_offset)] == search_word):
            print(f'[{known_offset},{limit}]\nLine: {line}\n{text}')
        file_offset += line_length

输出:

[61,67]
Line: 2
Ceci est une deuxième phrase barley.

【讨论】:

  • 我认为在这里,您的答案是您考虑单个句子的每个偏移量。就像我之前提到的,我要查找的偏移量是从句首到我们要查找的单词的连续偏移量。
  • 我对你的问题的理解是你知道单词的偏移量,你想得到符合这个条件的句子。您正在提供从行首和单词开始的偏移量。如果您不知道单词的偏移量,而是在文本文件中查找单词出现的行列表,包括从每行开头的偏移量,我不会在 Python 中实现该解决方案。相反,我会使用像 awk 这样的工具,因为它可以更好地扩展。
  • Nagel--当偏移量从一开始就连续计数时,你能提出一个解决方案吗?就像我在问题中提到的大麦这个词。
  • 您想在您的文本文件中查找单词barley 的位置吗?
  • Nagel--我想通过知道它的偏移量来找到每个单词的原句。请注意,我这里提到的偏移量必须在文本文件中连续计数。
【解决方案2】:

如果您已经知道单词的位置,那么标记化不是您想要做的。通过标记化,您将序列(您知道位置)更改为单词列表,您不知道哪个元素是您的单词。

因此,您应该将其留在短语中,并将短语的部分与您的单词进行比较:

with open("test.txt") as f:
    list_phrase = f.readlines()
    f.seek(0)
    contents = f.read()
    for index, phrase in enumerate(list_phrase):
        if phrase[13:18].lower() == "wheat": ## .lower() is only necessary if the word might be in upper case.
            print(list_phrase[index])

这只会返回wheat 位于[13:18] 位置的句子。不会识别所有其他出现的小麦。

【讨论】:

  • 我测试过了。它打印了 3 个错误的句子。它应该只打印一个句子。
  • 哦,对不起。我混淆了两个变量。应该是:phrase[13:18],而不是 contents[13:18]。我在上面的代码中更改了它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-14
  • 1970-01-01
  • 2016-12-27
  • 1970-01-01
  • 2012-07-19
  • 2021-06-28
相关资源
最近更新 更多