Изменение символа в строке в Lua - PullRequest
6 голосов
/ 09 марта 2011

Есть ли способ заменить символ в позиции 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 ]

12 голосов
/ 10 марта 2011

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

Это вариант вашего кода:

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

- самый прямой перевод на простой Lua. Это, вероятно, достаточно быстро для большинства целей. Я исправил ошибку, заключающуюся в том, что префикс должен быть первым pos-1 символом, и воспользовался тем, что, если отсутствует последний аргумент 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 может иметь проблемы с любыми символами \0 в любой строке, которую он передает в формате %s. В частности, поскольку она реализована в терминах стандартной функции C sprintf(), было бы разумно ожидать, что она завершит замещенную строку при первом появлении \0. (Отмечено пользователем Бредовая логика в комментарии.)

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

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

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

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

5 голосов
/ 09 марта 2011

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

Может быть,

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

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

0 голосов
/ 18 сентября 2018

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

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