如何在 Crystal 中读取一定数量的字符(而不是字节)?

How to read a certain number of characters (as opposed to bytes) in Crystal?

在Crystal中,如果我有一个字符串(或文件),如何一次读取一定数量的字符 ? 使用 IO#readIO#getsIO#read_stringIO#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 成为用于字符串大小写的 class,但据我所知,它的方法不允许这样做。 如何以一种高效和惯用的方式做到这一点(对于字符串和文件——也许每个答案都不同)in Crystal?

这个解决方法似乎对我有用:

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
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 中没有对此可用的快捷方式实现。

您可以使用 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 都是无关紧要的,行为都是一样的。

除了已经给出的答案之外,对于 Crystal 中的字符串,您可以读取 X 数量的字符,范围如下:

  my_string = "A foo, a bar."
  my_string[0..5] => "A foo"