#arrays #ruby #string #split
#массивы #ruby #строка #разделить
Вопрос:
Допустим, у меня есть строка
string = "hellohellohey"
Я хочу разделить ее на каждый 2-й символ, чтобы это выглядело так
string = ["he","ll","oh","el","lo","he","y"]
Я пытался использовать scan(/.{2}/)
метод, но если элемент массива не может быть разделен на 2, он не работает.
Редактировать: Необходимо сообщить вам, что 2-символьная вещь была примером. Я делаю что-то большое, поэтому я буду разделять его каждые 8 миллионов символов. Поэтому разделение ее на отдельные символы и использование each_slice
здесь не работает. Это просто замораживает мой ноутбук.
Комментарии:
1. Попробуйте использовать
.{1,2}
для сопоставления 1 или 2 раза.
Ответ №1:
При обработке (очень) больших строк может быть полезно обернуть их в StringIO
. Это обеспечивает эффективный файловый доступ к строке.
Вы можете, например, прочитать все n символов через StringIO#each
:
string = "hellohellohey"
string_io = StringIO.new(string)
string_io.each(5) do |substring|
p substring
end
Вывод:
"hello"
"hello"
"hey"
Комментарии:
1. Спасибо, это работает. Однако, это говорит мне, что это перечислитель, когда я пытаюсь подсчитать количество элементов в массиве. Редактировать: Неважно, я использовал
.to_a
2. @tequila это ожидаемо. С помощью блока
StringIO#each
выводятся символы / подстроки. Без блока он возвращает перечислитель. Я предположил, что вы хотите пропустить создание массива и работать с подстроками.
Ответ №2:
Точка соответствует любому символу, кроме новой строки. Вы пытаетесь сопоставить любой символ 2 раза, и это не будет соответствовать последнему символу, если строка нечетная по длине.
Вы могли бы использовать квантификатор {1,2}
, который является жадным, поэтому он сначала пытается сопоставить 2 раза.
.{1,2}
Смотрите демонстрацию
Если вы хотите сопоставлять только символы нижнего регистра от a до z, вы также можете использовать [a-z]
вместо точки.
Комментарии:
1. Также работает:
/..?/
это всего лишь еще один символ.{}
Версия, которая у вас есть здесь, более гибкая, так как вы могли бы сделать2,5
или9,300
или все, что вам нужно.2. Кроме того, вы, вероятно, захотите добавить
m
модификатор, чтобы он.
соответствовал любому символу (по умолчанию он не соответствует новой строке).
Ответ №3:
Вы можете объединить несколько методов, как показано ниже:
string = 'hellohellohey'
string.chars.each_slice(2).map { |s| s.join }
# => ["he", "ll", "oh", "el", "lo", "he", "y"]
#chars преобразует строку в массив символов.
#each_slice разбивает массив на необходимое количество частей.
Обновление — без промежуточного / временного массива
Согласно комментариям, благодаря @Cary Swoveland, временного массива можно избежать следующим образом.
string.each_char.each_slice(2).map { |s| s.join }
#each_char предоставляет перечислитель каждого символа.
Комментарии:
1. Небольшая точка, настолько маленькая, что она едва различима: я предлагаю вам использовать
each_char
вместоchars
, когда за ним следуетEnumerable
метод, чтобы избежать создания временного массиваstring.chars
.2. Я понял вашу точку зрения @CarySwoveland, я начал с того же, но затем я не смог собрать 2 / требуемое количество символов символов после
each_char
. можете ли вы как-то связать ее в цепочку?3.
string.each_char.each_slice(2).map { |s| s.join }
. Обратите внимание на возвращаемое значениеstring.each_char.each_slice(2) #=> #<Enumerator: #<Enumerator: "hellohellohey":each_char>:each_slice(2)>
, своего рода составной перечислитель .4. Помогает ли разделение строки, скажем, на 10000 символов за раз?
string[0..10000]