在Crystal中,如果我有一个字符串(或文件(,如何一次读取一定数量的字符使用IO#read
、IO#gets
、IO#read_string
和IO#read_utf8
等函数,可以指定要读取的字节数,但不能指定UTF-8字符数(或其他编码的字符数(。
例如,在Python中,可以这样做:
from io import StringIO
s = StringIO("abcdefgh")
while True:
chunk = s.read(4)
if not chunk: break
或者,在文件的情况下,这是:
with open("example.txt", 'r') as f:
while True:
chunk = f.read(4)
if not chunk: break
通常,我希望IO::Memory
是用于字符串大小写的类,但据我所知,它的方法不允许这样做在Crystal中,如何以高效且惯用的方式(对于字符串和文件,可能每个答案都不同(
目前在Crystal中没有这方面的捷径实现。
您可以用IO#read_char
读取单个字符,也可以用IO#each_char
读取连续字符。
因此,一个基本的实现是:
io = IO::Memory.new("€abcdefgh")
string = String.build(4) do |builder|
4.times do
builder << io.read_char
end
end
puts string
无论你使用内存IO、文件还是任何其他IO都无关紧要,行为都是一样的。
io = IO::Memory.new("€€€abc€€€") #UTF-8 string from memory
or
io = File.open("test.txt","r") #UTF-8 string from file
iter = io.each_char.each_slice(4) #read max 4 chars at once
iter.each { |slice| #into a slice
puts slice
puts slice.join #join to a string
}
output:
['€', '€', '€', 'a']
€€€a
['b', 'c', '€', '€']
bc€€
['€']
€
除了已经给出的答案外,对于Crystal中的字符串,您可以读取X个字符,范围如下:
my_string = "A foo, a bar."
my_string[0..5] => "A foo"
这个解决方法似乎对我有效:
io = IO::Memory.new("abcdefghz")
chars_to_read = 2 # Number of chars to read
while true
chunk = io.gets(chars_to_read) # Grab the chunk of type String?
break if chunk.nil? # Break if nothing else to read aka `nil`
end