#ruby
#ruby
Вопрос:
Я хотел бы вырезать несколько символов из начала очень большой строки. Чтобы сэкономить мне немного памяти и времени, я хотел бы избежать создания ее копии, а просто позволить строке начинаться с этого более позднего индекса, как это было бы легко возможно в C, просто увеличив указатель на строку (массив).
Возможно ли это?
Комментарии:
1. Какие операции вы хотите выполнить над строкой после ее обрезки?
2. Я анализирую CSV с помощью FasterCSV, перехватываю MalformedCSVErrors и повторно обрабатываю CSV из строки после неправильно сформированной. Поэтому мне нужно вырезать начало CSV. Я знаю, что я мог бы также выполнить потоковый синтаксический анализ CSV из исходного файла, но наша архитектура этого не позволяет (пока).
3. Можете ли вы привести пример?
4. Конечно: gist.github.com/952883
Ответ №1:
Вы не можете использовать трюк «увеличить указатель на строку», но попробуйте это:
str = 'I would like to cut a number of characters from the beginning of a very large String'
str[0, 10] = ''
str # => "ke to cut a number of characters from the beginning of a very large String"
Это самый простой из известных мне способов обрезать часть строки в Ruby.
Ответ №2:
Вероятно, невозможно сделать то, что вы хотели бы, из-за способа, которым Ruby представляет строки.
Как вы упомянули, в C вы могли бы просто увеличить указатель на строку на некоторое количество символов. Однако в Ruby класс String реализован с помощью, struct RString
который имеет ptr
поле для базовой строки C. Для Ruby не имело бы смысла предоставлять метод, который увеличивает поле ptr, потому что это привело бы к потере отслеживания исходного местоположения и усложнило бы освобождение этой памяти. Возможно, вы сможете написать свое собственное расширение для класса String, которое делает то, что вы хотите, но, вероятно, возникнут дополнительные сложности (например, в отношении хеширования).
Комментарии:
1. На самом деле, это возможно и
lstrip!
реализовано таким образом . (Не будучи специалистом по C, не могу сказать, как выполняется освобождение)
Ответ №3:
Если с памятью проблем нет и вам нужно избавиться от операции копирования, почему бы не создать свой собственный класс String, реализованный как array:
class StringAsArray
def initialize(s)
@arr = s.split(//)
end
// .... your methods goes here ....
end
Должно быть легко создавать методы для обрезки и т.д. Это очень наивный подход и, возможно, вам не подойдет. Зависит от того, что вам нужно сделать.
Комментарии:
1. «Если память не является проблемой» разве мы не пытались сэкономить память в первую очередь? (И не похоже, что это решение экономит время)
Ответ №4:
Вы можете использовать gsub!
, если знаете, какую часть нужно удалить.
s = 'cut this string'
s.gsub!('cut ', '')
s
# => "cut this string"
или вы можете использовать slice!
s.slice!(s.index('this')..-1)
s
# => "cut this string"
Комментарии:
1. Вы уверены, что это позволяет избежать копирования строки?
2.
bang!
Версия изменяет строку на месте, не создавая копию.3. @Nikita Rybak Я ответил на вопрос. Если вы используете bang! версия, строка изменяется на месте без выделения нового экземпляра.
4. Object_id остается тем же самым. Но не означает ли это, что содержимое копируется в начало выделенной памяти? Или object_id не представляет адрес в памяти?
Ответ №5:
Не совсем уверен, что строка #reverse! не копирует внутренне, но это метод, который я использовал в прошлом:
mystring.reverse!
num_of_chars.times {mystring.chop!}
mystring.reverse!
Хотя теперь, когда я смотрю на это, я думаю, что у Железного дровосека есть более элегантное решение.