【问题标题】:How to read values one whitespace separated value at a time?如何一次读取一个空格分隔的值?
【发布时间】:2022-01-02 21:28:53
【问题描述】:

在 C++ 中,您可以像这样一次读取一个值:

//from console
cin >> x;

//from file:
ifstream fin("file name");
fin >> x;

我想在 Python 中模拟这种行为。然而,在 Python 中获取输入的普通方法似乎是读取整行、整个文件或一组位数。

我想要一个函数,我们称之为one_read(),它从文件中读取,直到遇到空格或换行符,然后停止。此外,在随后对one_read() 的调用中,输入应该从它停止的地方开始。 它应该如何工作的示例:

# file input.in is:
# 5 4
# 1 2 3 4 5
n = int(one_read())
k = int(one_read())
a = []
for i in range(n):
    a.append(int(one_read()))
# n = 5 , k = 4 , a = [1,2,3,4,5]

我该怎么做?

【问题讨论】:

  • "在线搜索我只找到了逐行读取文件并拆分空格的选项。我想知道是否可以对控制台和文件输入执行此操作" 的当然是这样,因为无论您输入哪种方式,都会得到一个字符串,而策略是拆分字符串。无论字符串来自何处,它都以相同的方式工作。
  • "以及怎么做" 您应该已经知道如何从找到的结果中进行拆分。您应该已经知道如何从您找到的结果中逐行读取文件。你大概知道如何从控制台input()。所以我看不出你在哪里有真正的问题。您应该尝试编写代码,更仔细地阅读参考资料,并且只有在尝试失败并陷入调试和have tried everything else 时才提出特定问题。
  • 还请重新阅读How to Ask。我根据这些标准编辑了您的问题,以删除不相关的评论并明确提出问题。

标签: python input


【解决方案1】:

我认为以下内容应该让您接近。我承认我没有仔细测试过代码。听起来itertools.takewhile 应该是你的朋友,下面的yield_characters 这样的生成器会很有用。

from itertools import takewhile
import regex as re

# this function yields characters from a file one a at a time.
def yield_characters(file):
    with open(file, 'r') as f:
       while f:
           line = f.readline()
           for char in line:
              yield char

# double check this. My python regex is weak.
def not_whitespace(char):
    return bool(re.match(r"\S", char))

# this should use takewhile to get iterators while something is 
def read_one(file):
    chars = yield_character(file)
    while chars:
        yield list(takewhile(not_whitespace, chars)).join()

上面的read_one 是一个生成器,所以你需要在上面调用list。

【讨论】:

    【解决方案2】:

    通常您一次只阅读一行,然后split 这个并处理每个部分。但是,如果由于资源原因无法执行此操作,您可以实现自己的阅读器,它一次读取一个字符,然后 yield 每次到达分隔符时都会读取一个单词(或者在此示例中也是换行符或文件末尾)。

    此实现使用上下文管理器来处理文件打开/读取,尽管这可能有点矫枉过正:

    from functools import partial
    
    class Words():
        def __init__(self, fname, delim):
            self.delims = ['\n', delim]
            self.fname = fname
            self.fh = None
    
        def __enter__(self):
            self.fh = open(self.fname)
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.fh.close()
    
        def one_read(self):
            chars = []
            for char in iter(partial(self.fh.read, 1), ''):
               if char in self.delims:
                   # delimiter signifies end of word 
                   word = ''.join(chars)
                   chars = []
                   yield word
               else:
                   chars.append(char)
    
    # Assuming x.txt contains 12 34 567 8910
    with Words('/tmp/x.txt', ' ') as w:
        print(next(w.one_read()))
        # 12
        print(next(w.one_read()))
        # 34 
        print(list(w.one_read()))
        # [567, 8910]
    

    【讨论】:

      【解决方案3】:

      在 Python 中对文件进行操作的任何东西或多或少都可以对标准输入和标准输出进行操作。 sys 标准库模块定义了 stdin 和 stdout,它们使您可以将这些流作为类文件对象访问。

      一次读取一行在 Python 中被认为是惯用的,因为另一种方式很容易出错 (just one C++ example question on Stack Overflow)。但如果你坚持:你将不得不自己构建它。

      如您所见,.read(n) 最多只能从以文本模式打开的流中读取 n 文本字符(技术上是 Unicode 代码点)。在您阅读空格之前,您无法知道单词的结尾在哪里,但您可以 .seek 后退一个位置 - 尽管不是在标准输入上,这是不可搜索的。

      您还应该知道,在提示用户之前,内置的input 会忽略标准输入中的任何现有数据:

      >>> sys.stdin.read(1) # blocks
      foo
      'f'
      >>> # the `foo` is our input, the `'f'` is the result
      >>> sys.stdin.read(1) # data is available; doesn't block
      'o'
      >>> input()
      bar
      'bar'
      >>> # the second `o` from the first input was lost
      

      【讨论】:

        【解决方案4】:

        尝试创建一个类来记住操作停止的位置。

        __init__ 函数采用文件名,您可以修改它以采用列表或其他可迭代对象。

        read_one 检查是否还有要读取的内容,如果有,则删除并返回列表中索引 0 处的项目;直到第一个空格为止。

        class Reader:
            def __init__(self, filename):
                self.file_contents = open(filename).read().split()
        
            def read_one(self):
                if self.file_contents != []:
                    return self.file_contents.pop(0)
        

        按如下方式初始化函数并适应你的喜好:

        reader = Reader(filepath)
        reader.read_one()
        

        【讨论】:

        • 这个坏了。它实际上并没有让客户端代码知道“读取”的单词是什么,而是预先读取整个文件 - 这完全违背了尝试一次读取一个单词的目的。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-20
        • 1970-01-01
        • 2019-07-14
        • 2023-03-26
        • 1970-01-01
        相关资源
        最近更新 更多