Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying a character in a string in Lua

Is there any way to replace a character at position N in a string in Lua.

This is what I've come up with so far:

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)

I can't use gsub either as that would replace every capture, not just the capture at position N.

like image 939
dotminic Avatar asked Mar 09 '11 17:03

dotminic


People also ask

How do I manipulate a string in Lua?

This library provides generic functions for string manipulation, such as finding and extracting substrings. When indexing a string, the first character has position 1. See Section 8.3for some examples on string manipulation in Lua. strfind (str, substr, [init, [end]]) Receives two string arguments, and returns a number.

What are special characters in Lua?

Before we can dive too far into the rest of our common string functions, we need to understand the basics of patterns and how to handle special characters in Lua. Special characters are things like newlines and tabs. Let’s go over special characters first since they’re the easiest.

How to convert a decimal to a character in Lua?

string.char () function in Lua programming Lua Server Side Programming Programming There are so many scenarios where you might want to convert a decimal value into a character representation. The character representation of a decimal or integer value is nothing but the character value, which one can interpret using the ASCII table.

What is the use of the escape sequence in Lua programming?

Escape sequence characters are used in string to change the normal interpretation of characters. For example, to print double inverted commas (""), we have used " in the above example. The escape sequence and its use is listed below in the table. Lua supports string to manipulate strings −.


2 Answers

Strings in Lua are immutable. That means, that any solution that replaces text in a string must end up constructing a new string with the desired content. For the specific case of replacing a single character with some other content, you will need to split the original string into a prefix part and a postfix part, and concatenate them back together around the new content.

This variation on your code:

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

is the most direct translation to straightforward Lua. It is probably fast enough for most purposes. I've fixed the bug that the prefix should be the first pos-1 chars, and taken advantage of the fact that if the last argument to string.sub is missing it is assumed to be -1 which is equivalent to the end of the string.

But do note that it creates a number of temporary strings that will hang around in the string store until garbage collection eats them. The temporaries for the prefix and postfix can't be avoided in any solution. But this also has to create a temporary for the first .. operator to be consumed by the second.

It is possible that one of two alternate approaches could be faster. The first is the solution offered by Paŭlo Ebermann, but with one small tweak:

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

This uses string.format to do the assembly of the result in the hopes that it can guess the final buffer size without needing extra temporary objects.

But do beware that string.format is likely to have issues with any \0 characters in any string that it passes through its %s format. Specifically, since it is implemented in terms of standard C's sprintf() function, it would be reasonable to expect it to terminate the substituted string at the first occurrence of \0. (Noted by user Delusional Logic in a comment.)

A third alternative that comes to mind is this:

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

table.concat efficiently concatenates a list of strings into a final result. It has an optional second argument which is text to insert between the strings, which defaults to "" which suits our purpose here.

My guess is that unless your strings are huge and you do this substitution frequently, you won't see any practical performance differences between these methods. However, I've been surprised before, so profile your application to verify there is a bottleneck, and benchmark potential solutions carefully.

like image 157
RBerteig Avatar answered Oct 16 '22 09:10

RBerteig


You should use pos inside your function instead of literal 1 and 3, but apart from this it looks good. Since Lua strings are immutable you can't really do much better than this.

Maybe

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

is more efficient than the .. operator, but I doubt it - if it turns out to be a bottleneck, measure it (and then decide to implement this replacement function in C).

like image 25
Paŭlo Ebermann Avatar answered Oct 16 '22 11:10

Paŭlo Ebermann