Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lua: Substitute list of characters in string

Is it possible to substitute characters according to a list in Lua, like tr in Perl? For example, I would like to substitute A to B and B to A (e.g. AABBCC becomes BBAACC).

In Perl, the solution would be $str ~= tr/AB/BA/. Is there any native way of doing this in Lua? If not, I think the best solution would be iterating through the entire string, since separate substitutions need to use a special symbol to distinguish characters that were already substituted and characters that weren't.

Edit: my goal was to calculate the reverse complement of a DNA string, as described here.

like image 462
Fábio Perez Avatar asked Nov 05 '13 04:11

Fábio Perez


People also ask

What does GSUB do in Lua?

gsub (s, pattern, repl [, n]) Returns a copy of s in which all (or the first n , if given) occurrences of the pattern have been replaced by a replacement string specified by repl , which can be a string, a table, or a function. gsub also returns, as its second value, the total number of matches that occurred.

What is% s in Lua?

According to the documentation, %s means whitespace, and %S means anything other than whitespace. So that match expression will split on one or more whitespace characters, capturing the two strings on either side.

How do I remove the last character of a string in Lua?

The easiest way is to use the built-in substring() method of the String class. In order to remove the last character of a given String, we have to use two parameters: 0 as the starting index, and the index of the penultimate character.


2 Answers

string.gsub can take a table as the third argument. The table is queried for each match, using the first capture as the key, and the associated value is used as the replacement string. If the value is nil, the match is not changed.

So you can build a helper table like this:

local s = "AABBCC"
local t = {A = "B", B = "A"}
local result = string.gsub(s, "[AB]", t)
print(result)

or this same one-liner:

print((string.gsub("AABBCC", "[AB]", {A = "B", B = "A"})))

Output:

BBAACC

For a one character pattern like "[AB]", "." can work as well because whatever not found in the table won't be changed. (But I don't think that's more efficient) But for some more complicated cases, a good pattern is needed.

Here is an example from Programming in Lua: this function substitutes the value of the global variable varname for every occurrence of $varname in a string:

function expand (s)
    return (string.gsub(s, "$(%w+)", _G))
end
like image 123
Yu Hao Avatar answered Oct 23 '22 16:10

Yu Hao


The code below will replace each character with a desired mapping (or leave alone if no mapping exists). You could modify the second parameter to string.gsub in tr to be more specific if you know the exact range of characters.

s = "AABBCC"
mappings = {["A"]="B",["B"]="A"}

function tr(s,mappings)
    return string.gsub(s,
        "(.)",
        function(m)
            -- print("found",m,"replace with",mappings[m],mappings[m] or m)
            if mappings[m] == nil then return m else return mappings[m] end
        end 
    )
end

print(tr(s,mappings))

Outputs

henry@henry-pc:~/Desktop$ lua replace.lua
found   A   replace with    B   B
found   A   replace with    B   B
found   B   replace with    A   A
found   B   replace with    A   A
found   C   replace with    nil C
found   C   replace with    nil C
BBAACC  6
like image 21
HennyH Avatar answered Oct 23 '22 17:10

HennyH