Duplicates In a String - string

I need to write a function that takes a string and returns it with duplicate characters removed in Lua. What I need help with is...
Making a hash with letters and the counts
Making each letter equal to only one, deleting more than one occurrence
Converting hash into the new string with duplicates removed
A simple function/algorithm would be appreciated!

If you only need one instance of each character then you probably don't need to keep track of the counts; you can compare the input string against the same table you use to generate the output.
local function contains(tbl, val)
for k,v in pairs(tbl) do
if v == val then return true end
end
return false
end
local function uniq(str)
local out = {}
for s in str:gmatch(".") do
if not contains(out, s) then out[#out+1] = s end
end
return table.concat(out)
end
print( uniq("the quick brown fox jumps over the lazy dog") )
-- the quickbrownfxjmpsvlazydg
This will probably be slower than the function below for short strings, but it's generally best to avoid excessive string concatenation in Lua, for the reasons outlined here. If you're sure the output string will be fairly short, you can get rid of contains() and use this:
local function uniq(str)
local out = ""
for s in str:gmatch(".") do
if not out:find(s) then out = out .. s end
end
return out
end

Related

Lua string to table

I have a string that I need to read as a table
notes = "0,5,10,16"
so if I need the 3rd value of the current notes that is 10
value = notes[3]
If you trust the strings, you can reuse the Lua parser:
notes = "0,5,10,16"
notes = load("return {"..notes.."}")()
print(notes[3])
For the example string, you can just do
local notes_tab = {}
for note in notes:gmatch("%d*") do
table.insert(notes_tab, tonumber(note))
end
We can change the __index metamethod of all strings to return the nth element separated by commas. Doing this, however, gives the problem that we cannot do something like notes:gmatch(",?1,?") anymore. See this old StackOverflow post. It can be solved, by checking whether the __index is called with a string or other value.
notes = "0,5,10,16"
getmetatable("").__index = function(str, key)
if type(key) == "string" then
return string[key]
else
next_value = string.gmatch(str, "[^,]+")
for i=1, key - 1 do
next_value()
end
return next_value()
end
end
print(notes[3]) --> 10
string.gmatch returns a function over which we can iterate, so calling this n times will result in the nth number being returned.
The for loop makes sure that all the numbers before which we want have been iterated over by the gmatch.
Depending on what you want to do with the numbers you can either return it as a string or convert it to a number immediately.

Lua: delete specific characters in a string

I have a string that includes all the characters which should be
deleted in a given string. With a nested loop I can iterate through
both strings. But is there a shorter way?
local ignore = "'`'"
function ignoreLetters( c )
local new = ""
for cOrig in string.gmatch(c,".") do
local addChar = 1
for cIgnore in string.gmatch(ignore,".") do
if cOrig == cIgnore then
addChar = 0
break -- no other char possible
end
end
if addChar>0 then new = new..cOrig end
end
return new
end
print(ignoreLetters("'s-Hertogenbosch"))
print(ignoreLetters("'s-Hertogen`bosch"))
The string ignore can also be a table if it makes the code shorter.
You can use string.gsub to replace any occurance of a given string in a string by another string. To delete the unwanted characters, simply replace them with an empty string.
local ignore = "'`'"
function ignoreLetters( c )
return (c:gsub("["..ignore.."]+", ""))
end
print(ignoreLetters("'s-Hertogenbosch"))
print(ignoreLetters("'s-Hertogen`bosch"))
Just be aware that in case you want to ignore magic characters you'll have to escape them in your pattern.
But I guess this will give you a starting point and leave you plenty of own work to perfect.

Split string in Lua and print selected keys

I'm looking for a little help with splitting a string using Lua and printing selected parts of it. I have this code so far:
b = "an example string"
for i in string.gmatch(b, "%w+") do
print(i)
end
Output is...
an
example
string
How do I go about printing only bits of the result?
I've tried the following but just returns a list of "nils":
b = "an example string"
for i in string.gmatch(b, "%w+") do
print(i[1])
end
So if I wanted to print:
string
example
How would this work? I was pretty sure I just added the value assigned to the key that is in memory, like [0] or [1]. But I must be wrong..
In this use case the sample text will remain the same, only time stamps will change in the string. I just need to reorder the words.
Any help is greatly appreciated :)
The best way I can find is to use the loop to store the matches in an array. Then you can access them with literal indexes:
b = "an example string"
local words = {}
for i in string.gmatch(b, "%w+") do
table.insert(words, i)
end
print(words[3])
print(words[2])
In addition to the existing (probably perferable) answer, you could also do some manual work with a counter:
counter = 0
for i in string.gmatch(b, "%w+") do
counter = counter + 1
if counter > 1 then print(i) end
end
Or, here's a one-liner (that wouldn't scale with larger strings though and also doesn't insert a newline between second and third word):
print(string.match(b, "%w+%s+(%w+)%s+(%w+)"))

How to validate this string when we don't have the `|` operator in Lua?

I have strings of the form:
cake!apple!
apple!
cake!juice!apple!cake!
juice!cake!
In other words, these strings are composed of the three sub-strings "cake!", "apple!" and "juice!".
I need to validate these strings. The way to do this with a regular expression is thus:
/^(apple!|juice!|cake!)*$/
But Lua's patterns don't have the | operator, so it seemingly can't be done this way.
How can I validate my strings in Lua?
(I don't care about the contents of the strings: I only care about whether they conform (validate) or not.)
I know to write the code to do this but I can't think of a short way to do this. I'm looking for a short solution. I wonder if there's an elegant solution that I'm not aware of. Any ideas?
if str:gsub("%w+!", {["apple!"]="", ["juice!"]="", ["cake!"]=""}) == "" then
--do something
end
This solution uses a table as the second parameter to string.gsub. Since the patterns all match %w+, the table will validate for second time, only the real three patterns are replaced with an empty string. If after all the replacement, the string becomes empty, then the match succeeds.
Using a helper table variable can make it more clear:
local t = {["apple!"]="", ["juice!"]="", ["cake!"]=""}
if str:gsub("%w+!", t) == "" then
--do something
end
If there is a character that will never be in your string, for instance, the character "\1"(ASCII 1) is unlikely in a normal string, you can use this:
local str = "cake!juice!apple!cake!"
if str:gsub("apple!","\1"):gsub("juice!","\1"):gsub("cake!","\1"):gsub("\1","") == "" then
--do something
end
By replacing every match of the patterns to "\1", and finally replace "\1" to an empty string, the correct match would be an empty string in the end.
It has flaws(sometimes it's impossible to find a character that is never in the string), but I think it works in many situations.
The following seems to work for (the included) quick tests.
local strs = {
"cake!apple!",
"bad",
"apple!",
"apple!bad",
" apple!bad",
"cake!juice!apple!cake!",
"cake!juice! apple!cake!",
"cake!juice!badapple!cake!",
"juice!cake!",
"badjuice!cake!",
}
local legalwords = {
["cake!"] = true,
["apple!"] = true,
["juice!"] = true,
}
local function str_valid(str)
local newpos = 1
for pos, m in str:gmatch("()([^!]+!)") do
if not legalwords[m] then
return
end
newpos = pos + m:len()
end
if newpos ~= (str:len() + 1) then
return nil
end
return true
end
for _, str in ipairs(strs) do
if str_valid(str) then
print("Match: "..str)
else
print("Did not match: "..str)
end
end
Just to provide another answer, you can do this easily with lpeg's re module:
re = require 're'
local testdata =
{
"cake!apple!",
"apple!",
"cake!juice!apple!cake!",
"cake!juice!badbeef!apple!cake!",
"juice!cake!",
"badfood",
}
for _, each in ipairs(testdata) do
print(re.match(each, "('cake!' / 'apple!' / 'juice!')*") == #each + 1)
end
This outputs:
true
true
true
false
true
false
This looks almost like your regex pattern above minus the ^ $ of course since lpeg matching is always anchored.
Lua patterns are not a replacement for regular expressions, and cannot represent this sort of pattern. In this case, you just need to repeatedly make sure the front of the string matches one of your words and then pop it off, but you probably already knew that.
Something like:
local words = {cake=1,apple=2,juice=3}
local totals = {}
local matches = 0
local invalid = 0
string.gsub("cake!","(%a+)!",
function(word)
local index = words[word]
if index then
matches = matches + 1
totals[index] = totals[index] + 1
else
invalid = invalid + 1
end
end
)
if matches > 0 and invalid == 0 then
-- Do stuff
end
This will pass each word to the supplied function where you can validate each one.
I dont know if it'll help you to get by you problem. But using string.find() i could use "or". look:
str="juice!"
print(string.find(str, "cake!" or "teste"))
best regards

String manipulation in Lua: Swap characters in a string

I'm trying to do a function in Lua that swaps the characters in a string.
Can somebody help me ?
Here is an example:
Input = "This LIBRARY should work with any string!"
Result = "htsil biaryrs ohlu dowkrw ti hna ytsirgn!"
Note: The space is also swapped
Thank You Very Much :)
The simplest and clearest solution is this:
Result = Input:gsub("(.)(.)","%2%1")
This should do it:
input = "This LIBRARY should work with any string!"
function swapAlternateChars(str)
local t={}
-- Iterate through the string two at a time
for i=1,#str,2 do
first = str:sub(i,i)
second = str:sub(i+1,i+1)
t[i] = second
t[i+1] = first
end
return table.concat(t)
end
print(input)
print(swapAlternateChars(input))
Prints:
This LIBRARY should work with any string!
hTsiL BIARYRs ohlu dowkrw ti hna ytsirgn!
If you need the output as lower case you could always end it with:
output = swapAlternateChars(input)
print(string.lower(output))
Note, in this example, I'm not actually editing the string itself, since strings in Lua are immutable. Here's a read: Modifying a character in a string in Lua
I've used a table to avoid overhead from concatenating to a string because each concatenation may allocate a new string in memory.

Resources