如何一次读取一个空格分隔的值?

How to read values one whitespace separated value at a time?

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

//from console
cin >> x;

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

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

我想要一个函数,我们称它为 one_read(),它从文件中读取数据,直到遇到白色 space 或换行符,然后停止。此外,在对 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]

我该怎么做?

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

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

read_one 检查是否还有任何内容需要阅读,如果有,则删除并 returns 列表中索引 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()

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

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

如您所见,.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

通常您一次只读一行,然后 split 阅读每一部分。但是,如果由于资源原因您不能这样做,您可以实现自己的 reader 一次读取一个字符,然后每次到达分隔符时 yield 一个单词(或在此例如换行符或文件末尾)。

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

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]

我认为下面的内容应该能让您接近。我承认我没有仔细测试代码。听起来 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 之类的操作。