I want to replace \n with a space in a String with a recursive function using pattern matching, but I can't figure out how to match the \ char.
This is my function:
replace :: String -> String
replace ('\\':'n':xs) = ' ' : replace xs
replace (x:xs) = x : replace xs
replace "" = ""
In ('\':'n':xs) the backslash would escape the single quote and mess up the code, so I wrote ('\\':'n':xs) expecting that the first \ would escape the escape of the second \ and would match a backslash in a String. However, it doesn't.
This is what happens when I try the function in GHCi:
*Example> replace "m\nop"
"m\nop"
*Example> replace "m\\nop"
"m op"
How can I match a single backslash?
\n is a single character. If we use \n in a string like "Hello\nWorld!", then the resulting list looks like this: ['H','e','l','l','o','\n','W','o','r','l','d','!']. \n denotes a newline character, a single ASCII byte 10. However, since a newline isn't really easy to type in many programming languages, the escape sequence \n is used instead in string literals.
If you want to pattern match on a newline, you must use the whole escape sequence:
replace :: String -> String
replace ('\n':xs) = ' ' : replace xs
replace (x:xs) = x : replace xs
replace "" = ""
Otherwise, you will only match the literal \.
Exercise: Now that replace works, try to use map instead of explicit recursion.
Related
For example, if you have escaped string like
Hello wo\\\\rld.txt
you want to unescape it and make it, Hello wo\\rld.txt
essentially making,
\\ -> \, \\r -> \r, \\n -> \n,
etc
I tried doing string replace like:
out = out.replace("\\", "\");
but that is syntax error
You still have to escape every \ in your string literals i.e. out = out.replace("\\\\", "\\");
I used string.gsub(str, "%s+") to remove spaces from a string but not remove new lines, example:
str = "string with\nnew line"
string.gsub(str, "%s+")
print(str)
and I'm expecting the output to be like:
stringwith
newline
what pattern should I use to get that result.
It seems you want to match any whitespace matched with %s but exclude a newline char from the pattern.
You can use a reverse %S pattern (that matches any non-whitespace char) in a negated character set, [^...], and add a \n there:
local str = "string with\nnew line"
str = string.gsub(str, "[^%S\n]+", "")
print(str)
See an online Lua demo yielding
stringwith
newline
"%s" matches any whitespace character. if you want to match a space use " ". If you want to define a specific number of spaces either explicitly write them down " " or use string.rep(" ", 5)
I'm trying to write something that reads Lambda expressions and outputs a beta reduced version. Lambdas will be typed as follows : \variable -> expression and applications will be of the form (expression) (expression). So if '\' is found at the beginning of the string it knows to process a Lambda and if '(' is found it knows to process an application.
I have a type for Lambda Expressions defined:
data Expression = Variable String
| Lambda Expression Expression
| Apply Expression Expression
Here's my first attempt at writing a function for reading the input
processInput :: String -> Expression
processInput ('\':input) = processLambda input
processInput ('(':input) = processApply input
processInput str = Variable str
When I try to load this function I get
lexical error in string/character literal at ':'
So I tried using guards instead:
processInput input
| head input == '\' = processLambda (tail input)
| head input == '(' = processApply (tail input)
| otherwise = Variable input
But got
lexical error in string/character literal at character ' '
I have no idea what's wrong with either of these functions.
The backslash is a special character in string and character literals. You use to represent non-printable characters, line breaks and characters that would otherwise have special meaning in a literal. For example '\n' is a line break '\b' is a back space and '\'' is a single quote (without the \, the second ' would be seen as the end of the character literal).
So when you write '\', the lexer sees the start of a character literal, followed by an escaped '. Now it expects another ' to close the character literal, but gets a colon instead, causing the error.
To represent a backslash as a character literal, you escape the backslash with another backslash like this: '\\'.
The backslash is the escape character so it needs to be doubled up to represent a single backslash: '\\'.
processInput ('\\':input) = processLambda input
...
-- or...
processInput input
| head input == '\\' = processLambda (tail input)
...
Does string.gsub recognize the newline character in a string literal? I have a scenario in which I am trying to gsub a portion of a string indicated by a given operator from the start of the operator to the newline like so:
local function removeComments(str, operator)
local new_Sc = (str):gsub(operator..".*\n", "");
return new_Sc;
end
local source = [[
int hi = 123; //a basic comment
char ok = "abc"; //another comment
]];
source = removeComments(source, "//");
print(source);
however in the output I see that it removed the rest of the string literal after the first comment:
int hi = 123;
I tried using the literal newline character by using string.char(10) like so (str):gsub(operator..".*"..string.char(10), ""); however I still got the same output; it removes the comment and the rest of the string instead of the start of the comment to the newline.
So is there anyway to gsub a string literal for a pattern containing a newline character?
Thanks
The problem you are facing is akin to greedy vs. lazy matching in regular expressions (.* vs .*?).
In Lua patterns, X.*\n means "match X, then match as many as possible characters followed by a newline". gsub has no special handling for a newline, hence it will try to continue matching until the last newline, subbing as many characters as it can. You want to match as few characters as possible, which is represented by .- in Lua patterns.
Also, I am not sure if it is intended or not, but this strategy will not remove the comment from the last line, if it is not (properly) ended by a newline. I am not sure if it can be represented by a single pattern, but this function will remove comments from all lines:
local function removeComments(str, operator)
local new_Sc = str:gsub(operator..".-\n", "\n");
new_Sc = new_Sc:gsub(operator.."[^\n].*$", "");
return new_Sc;
end
I've hit s small block with string parsing. I have a string like:
footage/down/temp/cars_[100]_upper/cars_[100]_upper.exr
and I'm having difficulty using gsub to delete a portion of the string. Normally I would do this
lineA = footage/down/temp/cars_[100]_upper/cars_[100]_upper.exr
lineB = footage/down/temp/cars_[100]_upper/
newline = lineA:gsub(lineB, "")
which would normally give me 'cars_[100]_upper.exr'
The problem is that gsub doesn't like the [] or other special characters in the string and unlike string.find gsub doesn't have the option of using the 'plain' flag to cancel pattern searching.
I am not able to manually edit the lines to include escape characters for the special characters as I'm doing file a file comparison script.
Any help to get from lineA to newline using lineB would be most appreciated.
Taking from page 181 of Programming in Lua 2e:
The magic characters are:
( ) . % + - * ? [ ] ^ $
The character '%' works as an escape
for these magic characters.
So, we can just come up with a simple function to escape these magic characters, and apply it to your input string (lineB):
function literalize(str)
return str:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", function(c) return "%" .. c end)
end
lineA = "footage/down/temp/cars_[100]_upper/cars_[100]_upper.exr"
lineB = literalize("footage/down/temp/cars_[100]_upper/")
newline = lineA:gsub(lineB, "")
print(newline)
Which of course prints: cars_[100]_upper.exr.
You may use another approach like:
local i1, i2 = lineA:find(lineB, nil, true)
local result = lineA:sub(i2 + 1)
You can also escape punctuation in a text string, str, using:
str:gsub ("%p", "%%%0")