How to remove white spaces after "(" in string? - lua

A lua newbie here.
I would like to replace the string '$\\psi\\left( y\\right)$' with '$\\psi\\left(y\\right)$' i.e. remove any white spaces that show up after ( and before the next non-white space character.
I have been trying gsub but each attempt did not work. This is what I tried
function foo(s)
print('before s = '..s)
str=string.gsub(s,"\\left( ","\\left(")
print('after s= '..str)
return str
end
And tried
function foo(s)
print('before s = '..s)
str=string.gsub(s,"\\left(%s+","\\left(")
print('after s= '..str)
return str
end
And few other variations. But each time I call the function as follows
foo('$\\psi\\left( y\\right)$')
The string returned is the same. The white space is still there.
What is the correct way to do this? Using Lua 5.2.4 on linux.
I intend to use this function inside lualatex, and these strings will be passed from latex to lua as strings. But I am now trying this function in standalone lua installation on Linux first to see if it works before I use it inside Lualatex.

Magic characters like ( need to be escaped.
Please refer to https://www.lua.org/manual/5.3/manual.html#6.4.1
Replace "\\left(%s+" with "\\left%(%s+" or "\\left( +" with "\\left%( +"
Looks to me like some bug. This should actually result in an "unfinished capture" error. At least it would if ( was the first character in the pattern.

Related

Lua patterns become confused with unusual characters

So, I tried to separate text in Lua. The following code perfectly separates a string with "§§§" as a separator.
local t={}
for str in string.gmatch(inputstr, "([^§§§]+)") do
table.insert(t, str)
end
So when I set inputstr="One§§§Two§§§Three" t comes out as {One, Two, Three}
But then I needed to separate a text with a ` in it. If I set inputstr="One§§§Two´Three" t comes out as {One, Two, �Three}.
I don't mind the unknown character symbol, but it also separates the string there.
I also tried some other uncommon symbols, for example, emojis have the same problem.
Anyone had the same problem or knows a solution for this?

How can I use single and normal quotation marks in the same string?

I am working on a project, in which you type your input sentence, and I need to be able to use " and ' in the sentence, such as Input = "I said, "Hi what's up?" print(Input) in which I get an error. If anyone knows how to fix this that would be great.
See https://www.lua.org/pil/2.4.html. Lua has very interesting feature to declare string with square brackets:
input = [[I said, "Hi what's up?"]]
input = "I said, \"Hi what's up?\""
input = 'I said, "Hi what\'s up?"'
I will tell some things in addition to what #Darius told above
When you tried to add a quatation mark inside a string, the lua interpreter get confused and break your string after the next quation mark without reaching the end of the line. That's the reason for the error.
Try to understand it by the following code
str = "Hello I"m somebody" -- here the interpreter will think str equals to "Hello I" at first, and then it will find some random characters after which may make it confused (as m somebody is neither a variable nor a keyword)"
-- you can also see the way it got confused by looking at the highlighted code
--What you can do to avoid this is escaping the quotes
str = "Hello I\"m somebody" -- here the interpreter will treat \" as a raw character (") and parse the rest.
You can also use the escape character () with others such as \', \", \[, \n (newline character), \t (tab) and so on.

Lua string.find() error

So I'm writing a Lua script and I tested it but I got an error that I don't know how to fix:
.\search.lua:10: malformed pattern (missing ']')
Below is my code. If you know what I did wrong, it would be very helpful if you could tell me.
weird = "--[[".."\n"
function readAll(file)
local c = io.open(file, "rb")
local j = c:read("*all")
c:close()
return(j)
end
function blockActive()
local fc = readAll("functions.lua")
if string.find(fc,weird) ~= nil then
require("blockDeactivated")
return("false")
else
return("true")
end
end
print(blockActive())
Edit: first comment had the answer. I changed
weird = "--[[".."\n" to weird = "%-%-%[%[".."\r" The \n to \r change was because it was actually supposed to be that way in the first place.
This errors because string.find uses Lua Patterns.
Most non-alpha-numeric characters, such as "[", ".", "-" etc. convey special meaning.
string.find(fc,weird), or better, fc:find(weird) is trying to parse these special characters, and erroring.
You can use these patterns to cancel out your other patterns, however.
weird = ("--[["):gsub("%W","%%%0") .. "\r?\n"
This is a little daunting, but it will hopefully make sense.
the ("--[[") is the orignal first part of your weird string, working as expected.
:gsub() is a function that replaces a pattern with another one. Once again, see Patterns.
"%W" is a pattern that matches every string that isn't a letter, a number, or an underscore.
%%%0 replaces everything that matches with itself (%0 is a string that represents everything in this match), following a %, which is escaped.
So this means that [[ will be turned into %[%[, which is how find, and similar patterns 'escape' special characters.
The reason \n is now \r?\n refers back to these patterns. This matches it if it ends with a \n, like it did before. However, if this is running on windows, a newline might look like \r\n. (You can read up on this HERE). A ? following a character, \r in this case, means it can optionally match it. So this matches both --[[\n and --[[\r\n, supporting both windows and linux.
Now, when you run your fc:find(weird), it's running fc:find("%-%-%[%[\r?\n"), which should be exactly what you want.
Hope this has helped!
Finished code if you're a bit lazy
weird = ("--[["):gsub("%W","%%%0") .. "\r?\n" // Escape "--[[", add a newline. Used in our find.
// readAll(file)
// Takes a string as input representing a filename, returns the entire contents as a string.
function readAll(file)
local c = io.open(file, "rb") // Open the file specified by the argument. Read-only, binary (Doesn't autoformat things like \r\n)
local j = c:read("*all") // Dump the contents of the file into a string.
c:close() // Close the file, free up memory.
return j // Return the contents of the string.
end
// blockActive()
// returns whether or not the weird string was matched in 'functions.lua', executes 'blockDeactivated.lua' if it wasn't.
function blockActive()
local fc = readAll("functions.lua") // Dump the contents of 'functions.lua' into a string.
if fc:find(weird) then // If it functions.lua has the block-er.
require("blockDeactivated") // Require (Thus, execute, consider loadfile instead) 'blockDeactived.lua'
return false // Return false.
else
return true // Return true.
end
end
print(blockActive()) // Test? the blockActve code.

How to replace brackets in Lua using string.gsub?

I have a function which is used to replace some words with a few characters or numbers. I am using string.gsub() function in this way:
string.gsub(line, "[0-9%a%s/,-]+", "\t")
This works very good with strings with numbers, letters, spaces, ,, and /. I also would like to replace brackets like ( and ). But simply inserting () to my pattern doesn't work. I have also tried with %( and %) but it wasn't successful. How can I replace brackets in Lua using pattern in string.gsub() method?
The only characters that need to be escaped inside [] are []%-, all of which are escaped with %. As such, escaping - as follows works:
string.gsub(line, "[0-9%a%s/,%-()]+", "\t")
It's also probably worth mentioning that [0-9%a] is equivalent to [%d%a], which is equivalent to %w.

Escaping strings for gsub

I read a file:
local logfile = io.open("log.txt", "r")
data = logfile:read("*a")
print(data)
output:
...
"(\.)\n(\w)", r"\1 \2"
"\n[^\t]", "", x, re.S
...
Yes, logfile looks awful as it's full of various commands
How can I call gsub and remove i.e. "(\.)\n(\w)", r"\1 \2" line from data variable?
Below snippet, does not work:
s='"(\.)\n(\w)", r"\1 \2"'
data=data:gsub(s, '')
I guess some escaping needs to be done. Any easy solution?
Update:
local data = [["(\.)\n(\w)", r"\1 \2"
"\n[^\t]", "", x, re.S]]
local s = [["(\.)\n(\w)", r"\1 \2"]]
local function esc(x)
return (x:gsub('%%', '%%%%')
:gsub('^%^', '%%^')
:gsub('%$$', '%%$')
:gsub('%(', '%%(')
:gsub('%)', '%%)')
:gsub('%.', '%%.')
:gsub('%[', '%%[')
:gsub('%]', '%%]')
:gsub('%*', '%%*')
:gsub('%+', '%%+')
:gsub('%-', '%%-')
:gsub('%?', '%%?'))
end
print(data:gsub(esc(s), ''))
This seems to works fine, only that I need to escape, escape character %, as it wont work if % is in matched string. I tried :gsub('%%', '%%%%') or :gsub('\%', '\%\%') but it doesn't work.
Update 2:
OK, % can be escaped this way if set first in above "table" which I just corrected
:terrible experience:
Update 3:
Escaping of ^ and $
As stated in Lua manual (5.1, 5.2, 5.3)
A caret ^ at the beginning of a pattern anchors the match at the beginning of the subject string. A $ at the end of a pattern anchors the match at the end of the subject string. At other positions, ^ and $ have no special meaning and represent themselves.
So a better idea would be to escape ^ and $ only when they are found (respectively) and the beginning or the end of the string.
Lua 5.1 - 5.2+ incompatibilities
string.gsub now raises an error if the replacement string contains a % followed by a character other than the permitted % or digit.
There is no need to double every % in the replacement string. See lua-users.
According to Programming in Lua:
The character `%´ works as an escape for those magic characters. So, '%.' matches a dot; '%%' matches the character `%´ itself. You can use the escape `%´ not only for the magic characters, but also for all other non-alphanumeric characters. When in doubt, play safe and put an escape.
Doesn't this mean that you can simply put % in front of every non alphanumeric character and be fine. This would also be future proof (in the case that new special characters are introduced). Like this:
function escape_pattern(text)
return text:gsub("([^%w])", "%%%1")
end
It worked for me on Lua 5.3.2 (only rudimentary testing was performed). Not sure if it will work with older versions.
Why not:
local quotepattern = '(['..("%^$().[]*+-?"):gsub("(.)", "%%%1")..'])'
string.quote = function(str)
return str:gsub(quotepattern, "%%%1")
end
to escape and then gsub it away?
try
line = '"(\.)\n(\w)", r"\1 \2"'
rx = '\"%(%\.%)%\n%(%\w%)\", r\"%\1 %\2\"'
print(string.gsub(line, rx, ""))
escape special characters with %, and quotes with \
Try s=[["(\.)\n(\w)", r"\1 \2"]].
Use stringx.replace() from Penlight Lua Libraries instead.
Reference: https://stevedonovan.github.io/Penlight/api/libraries/pl.stringx.html#replace
Implementation (v1.12.0): https://github.com/lunarmodules/Penlight/blob/1.12.0/lua/pl/stringx.lua#L288
Based on their implementation:
function escape(s)
return (s:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]','%%%1'))
end
function replace(s,old,new,n)
return (gsub(s,escape(old),new:gsub('%%','%%%%'),n))
end

Resources