Изменение символа в строке в Lua

есть ли способ заменить символ в позиции N в строке в Lua.

вот что я придумал до сих пор:

function replace_char(pos, str, r)
    return str:sub(pos, pos - 1) .. r .. str:sub(pos + 1, str:len())
end

str = replace_char(2, "aaaaaa", "X")
print(str)

Я не могу использовать gsub, так как это заменит каждый захват, а не только захват в позиции N.

3 ответов


строки в Lua неизменяемы. Это означает, что любое решение, которое заменяет текст в строке, должно в конечном итоге создать новую строку с требуемым содержимым. Для конкретного случая замены одного символа другим содержимым вам нужно будет разделить исходную строку на префиксную часть и постфиксную часть и объединить их вокруг нового содержимого.

эта вариация вашего кода:

function replace_char(pos, str, r)
    return str:sub(1, pos-1) .. r .. str:sub(pos+1)
end

это самый прямой перевод простой Lua. Вероятно, это достаточно быстро для большинства целей. Я исправил ошибку, что префикс должен быть первым pos-1 chars, и воспользовался тем, что если последний аргумент string.sub отсутствует, предполагается, что -1 что эквивалентно концу строки.

но обратите внимание, что он создает ряд временных строк, которые будут висеть в хранилище строк, пока сборщик мусора не съест их. Временные для префикса и постфикса не могут избегайте в любом решении. Но это также должно создать временное для первого .. оператор, который будет потребляться вторым.

вполне возможно, что один из двух альтернативных подходов может быть быстрее. Первый-это решение, предлагаемое Paŭlo Ebermann, но с одной небольшой твик:

function replace_char2(pos, str, r)
    return ("%s%s%s"):format(str:sub(1,pos-1), r, str:sub(pos+1))
end

использует string.format сделать сборку результата в надежде, что он может угадать окончательный размер буфера без необходимости дополнительных временных объектов.

но остерегайтесь этого string.format вероятно, будут проблемы с любым символы в любой строке, которая проходит через его . В частности, поскольку он реализован в терминах стандарта C sprintf() функция, было бы разумно ожидать, что она завершит замещенную строку при первом появлении . (Отмечено пользователем Бредовая Логика в комментарии.)

третья альтернатива, которая приходит на ум это:

function replace_char3(pos, str, r)
    return table.concat{str:sub(1,pos-1), r, str:sub(pos+1)}
end

table.concat эффективно объединяет список строк в конечный результат. Он имеет необязательный второй аргумент, который является текстом для вставки между строками, который по умолчанию равен "" что соответствует нашей цели здесь.

Я предполагаю, что если ваши строки не огромны, и вы часто делаете эту замену, вы не увидите никаких практических различий в производительности между этими методами. Тем не менее, я был удивлен раньше, поэтому профилируйте свое приложение проверьте наличие узкого места и тщательно проверьте потенциальные решения.


вы должны использовать pos внутри вашей функции вместо literal 1 и 3, но кроме этого он выглядит хорошо. Поскольку строки Lua неизменяемы, вы не можете сделать намного лучше, чем это.

может быть

 "%s%s%s":format(str:sub(1,pos-1), r, str:sub(pos+1, str:len())

более эффективно, чем .. оператор, но я сомневаюсь в этом - если это окажется узким местом, измерьте его (а затем решите реализовать эту функцию замены в C).


С luajit вы можете использовать библиотеку FFI для приведения строки в список неподписанных диаграмм:

local ffi = require 'ffi'
txt = 'test'
ptr = ffi.cast('uint8_t*', txt)
ptr[1] = string.byte('o')