String Matching with newline character in Haskell - string

Here I am trying to find the index of '-' followed by '}' in a String.
For an input like sustringIndex "abcd -} sad" it gives me an output of 10
which is giving me the entire string length.
Also if I do something like sustringIndex "abcd\n -} sad" it gives me 6
Why is that so with \n. What am I doing wrong. Please correct me I'm a noob.
substrIndex :: String -> Int
substrIndex ""=0
substrIndex (s:"") = 0
substrIndex (s:t:str)
| s== '-' && t == '}' = 0
| otherwise = 2+(substrIndex str)

Your program has a bug. You are checking every two characters. But, what if the - and } are in different pairs, for example S-}?
It will first check S and - are equal to - and } respectively.
Since they don't match, it will move on with } alone.
So, you just need to change the logic a little bit, like this
substrIndex (s:t:str)
| s == '-' && t == '}' = 0
| otherwise = 1 + (substrIndex (t:str))
Now, if the current pair doesn't match -}, then just skip the first character and proceed with the second character, substrIndex (t:str). So, if S- doesn't match, your program will proceed with -}. Since we dropped only one character we add only 1, instead of 2.
This can be shortened and written clearly, as suggested by user2407038, like this
substrIndex :: String -> Int
substrIndex [] = 0
substrIndex ('-':'}':_) = 0
substrIndex (_:xs) = 1 + substrIndex xs

Related

How convert first char to lowerCase

Try to play with string and I have string like: "Hello.Word" or "stackOver.Flow"
and i what first char convert to lower case: "hello.word" and "stackOver.flow"
For snakeCase it easy we need only change UpperCase to lower and add '_'
but in camelCase (with firs char in lower case) i dont know how to do this
open System
let convertToSnakeCase (value:string) =
String [|
Char.ToLower value.[0]
for ch in value.[1..] do
if Char.IsUpper ch then '_'
Char.ToLower ch |]
Who can help?
module Identifier =
open System
let changeCase (str : string) =
if String.IsNullOrEmpty(str) then str
else
let isUpper = Char.IsUpper
let n = str.Length
let builder = new System.Text.StringBuilder()
let append (s:string) = builder.Append(s) |> ignore
let rec loop i j =
let k =
if i = n (isUpper str.[i] && (not (isUpper str.[i - 1])
((i + 1) <> n && not (isUpper str.[i + 1]))))
then
if j = 0 then
append (str.Substring(j, i - j).ToLower())
elif (i - j) > 2 then
append (str.Substring(j, 1))
append (str.Substring(j + 1, i - j - 1).ToLower())
else
append (str.Substring(j, i - j))
i
else
j
if i = n then builder.ToString()
else loop (i + 1) k
loop 1 0
type System.String with
member x.ToCamelCase() = changeCase x
printfn "%s" ("StackOver.Flow".ToCamelCase()) //stackOver.Flow
//need stackOver.flow
I suspect there are much more elegant and concise solutions, I sense you are learning functional programming, so I think its best to do stuff like this with recursive function rather than use some magic library function. I notice in your question you ARE using a recusive function, but also an index into an array, lists and recursive function work much more easily than arrays, so if you use recursion the solution is usually simpler if its a list.
I'd also avoid using a string builder, assuming you are learning fp, string builders are imperative, and whilst they obviously work, they wont help you get your head around using immutable data.
The key then is to use the pattern match to match the scenario that you want to use to trigger the upper/lower case logic, as it depends on 2 consecutive characters.
I THINK you want this to happen for the 1st char, and after a '.'?
(I've inserted a '.' as the 1st char to allow the recursive function to just process the '.' scenario, rather than making a special case).
let convertToCamelCase (value : string) =
let rec convertListToCamelCase (value : char list) =
match value with
| [] -> []
| '.' :: second :: rest ->
'.' :: convertListToCamelCase (Char.ToLower second :: rest)
| c :: rest ->
c :: convertListToCamelCase rest
// put a '.' on the front to simplify the logic (and take it off after)
let convertAsList = convertListToCamelCase ('.' :: (value.ToCharArray() |> Array.toList))
String ((convertAsList |> List.toArray).[1..])
The piece to worry about is the recusive piece, the rest of it is just flipping an array to a list and back again.

How to fix indentation problem with haskell if statement

I have the following Haskell code:
f :: Int -> Int
f x =
let var1 = there in
case (there) of
12 -> 0
otherwise | (there - 1) >= 4 -> 2
| (there + 1) <= 2 -> 3
where there = 6
The function alone is garbage, ignore what exactly it does.
I want to replace the guards with if
f x =
let var1 = there in
case (there) of
12 -> 0
otherwise -> if (there - 1) >= 4 then 2
else if (there + 1) <= 2 then 3
where there = 6
I tried moving the if to the next line, the then to the next line, lining them up, unlining them, but nothing seems to work.
I get a parsing error and I don't know how to fix it:
parse error (possibly incorrect indentation or mismatched brackets)
|
40 | where there = 6
| ^
You have a few misunderstandings in here. Let's step through them starting from your original code:
f x =
A function definition, but the function never uses the parameter x. Strictly speaking this is a warning and not an error, but most code bases will use -Werror so consider omitting the parameter or using _ to indicate you are explicitly ignoring the variable.
let var1 = there in
This is unnecessary - again you are not using var1 (the below used there) so why have it?
case (there) of
Sure. Or just case there of, not need for excessive parens cluttering up the code.
12 -> 0
Here 12 is a pattern match, and it's fine.
otherwise ->
Here you used the variable name otherwise as a pattern which will uncondtionally match the value there. This is another warning: otherwise is a global value equal to True so it can be used in guards, such as function foo | foo < 1 = expr1 ; | otherwise = expr2. Your use is not like that, using otherwise as a pattern shadows the global value. Instead consider the catch all pattern with underscore:
_ -> if (there - 1) >= 4
then 2
else if (there + 1) <= 2
then 3
where there = 6
Ok... what if there was equal to 3? 3-1 is not greater than 4. 3+1 is not less than 2. You always need an else with your if statement. There is no if {} in Haskell instead there is if ... else ... much like the ternary operator in C, as explained in the Haskell wiki.

Optional capture of balanced brackets in Lua

Let's say I have lines of the form:
int[4] height
char c
char[50] userName
char[50+foo("bar")] userSchool
As you see, the bracketed expression is optional.
Can I parse these strings using Lua's string.match() ?
The following pattern works for lines that contain brackets:
line = "int[4] height"
print(line:match('^(%w+)(%b[])%s+(%w+)$'))
But is there a pattern that can handle also the optional brackets? The following does not work:
line = "char c"
print(line:match('^(%w+)(%b[]?)%s+(%w+)$'))
Can the pattern be written in another way to solve this?
Unlike regular expressions, ? in Lua pattern matches a single character.
You can use the or operator to do the job like this:
line:match('^(%w+)(%b[])%s+(%w+)$') or line:match('^(%w+)%s+(%w+)$')
A little problem with it is that Lua only keeps the first result in an expression. It depends on your needs, use an if statement or you can give the entire string the first capture like this
print(line:match('^((%w+)(%b[])%s+(%w+))$') or line:match('^((%w+)%s+(%w+))$'))
LPeg may be more appropriate for your case, especially if you plan to expand your grammar.
local re = require're'
local p = re.compile( [[
prog <- stmt* -> set
stmt <- S { type } S { name }
type <- name bexp ?
bexp <- '[' ([^][] / bexp)* ']'
name <- %w+
S <- %s*
]], {set = function(...)
local t, args = {}, {...}
for i=1, #args, 2 do t[args[i+1]] = args[i] end
return t
end})
local s = [[
int[4] height
char c
char[50] userName
char[50+foo("bar")] userSchool
]]
for k, v in pairs(p:match(s)) do print(k .. ' = ' .. v) end
--[[
c = char
userSchool = char[50+foo("bar")]
height = int[4]
userName = char[50]
--]]

Haskell flag pattern writing function?

I really need help in writing this function in Haskell, I don't even know where to start. Here are the specs:
Define a function flagpattern that takes a positive Int value greater than or equal to five and returns a String that can be displayed as the following `flag' pattern of dimension n, e.g.
Main> putStr (flagpattern 7)
#######
## ##
# # # #
# # #
# # # #
## ##
#######
Assuming you want a "X" enclosed in 4 lines, you need to write a function that given a coordinate (x,y) returns what character should be at that position:
coordinate n x y = if i == 0 then 'X' else ' '
(This version outputs only the leftmost X'es, modify it, remember indices start with 0)
Now you want them nicely arranged in a matrix, use a list comprehension, described in the linked text.
You should start from your problem definition:
main :: IO ()
main = putStr . flagPattern $ 7
Then, you should ask yourself about how much dots flag has:
flagPattern :: Int -> String
flagPattern = magic $ [1..numberOfDots]
Then, (hard) part of magic function should decide for each dot whether it is   or #:
partOfMagic ...
| ... = "#" -- or maybe even "#\n" in some cases?
| otherwise = " "
Then, you can concatenate parts into one string and get the answer.
Start with the type signature.
flagpattern :: Int -> String
Now break the problem into subproblems. For example, suppose I told you to produce row 2 of a size 7 flag pattern. You would write:
XX XX
Or row 3 of a size 7 flag pattern would be
X X X X
So suppose we had a function that could produce a given row. Then we'd have
flagpattern :: Int -> String
flagpattern size = unlines (??? flagrow ???)
flagrow :: Int -> Int -> String
flagrow row size = ???
unlines takes a list of Strings and turns it into a single String with newlines between each element of the list. See if you can define flagrow, and get it working correctly for any given row and size. Then see if you can use flagrow to define flagpattern.

How can I extract the middle part of a string in FSharp?

I want to extract the middle part of a string using FSharp if it is quoted, similar like this:
let middle =
match original with
| "\"" + mid + "\"" -> mid
| all -> all
But it doesn't work because of the infix operator + in pattern expression. How can I extract this?
I don't think there is any direct support for this, but you can certainly write an active pattern. Active patterns allow you to implement your own code that will run as part of the pattern matching and you can extract & return some part of the value.
The following is a pattern that takes two parameters (prefix and postfix string) and succeeds if the given input starts/ends with the specified strings. The pattern is not complete (can fail), so we'll use the |Name|_| syntax and it will need to return option value:
let (|Middle|_|) prefix postfix (input:string) =
// Check if the string starts with 'prefix', ends with 'postfix' and
// is longer than the two (meaning that it contains some middle part)
if input.StartsWith(prefix) && input.EndsWith(postfix) &&
input.Length >= (prefix.Length + postfix.Length) then
// Strip the prefix/postfix and return 'Some' to indicate success
let len = input.Length - prefix.Length - postfix.Length
Some(input.Substring(prefix.Length, len))
else None // Return 'None' - string doesn't match the pattern
Now we can use Middle in pattern matching (e.g. when using match):
match "[aaa]" with
| Middle "[" "]" mid -> mid
| all -> all
Parameterized active patterns to the rescue!
let (|HasPrefixSuffix|_|) (pre:string, suf:string) (s:string) =
if s.StartsWith(pre) then
let rest = s.Substring(pre.Length)
if rest.EndsWith(suf) then
Some(rest.Substring(0, rest.Length - suf.Length))
else
None
else
None
let Test s =
match s with
| HasPrefixSuffix("\"","\"") inside ->
printfn "quoted, inside is: %s" inside
| _ -> printfn "not quoted: %s" s
Test "\"Wow!\""
Test "boring"
… or just use plain old regular expression
let Middle input =
let capture = Regex.Match(input, "\"([^\"]+)\"")
match capture.Groups.Count with
| 2 -> capture.Groups.[1].Value
| _ -> input
Patterns have a limited grammar - you can't just use any expression. In this case, I'd just use an if/then/else:
let middle (s:string) =
if s.[0] = '"' && s.[s.Length - 1] = '"' && s.Length >= 2 then
s.Substring(1,s.Length - 2)
else s
If grabbing the middle of a string with statically known beginnings and endings is something that you'll do a lot, then you can always use an active pattern as Tomas suggests.
Not sure how efficient this is:
let GetQuote (s:String) (q:char) =
s
|> Seq.skip ((s |> Seq.findIndex (fun c -> c = q))+1)
|> Seq.takeWhile (fun c-> c <> q)
|> Seq.fold(fun acc c -> String.Format("{0}{1}", acc, c)) ""
Or there's this with Substring in place of the fold:
let GetQuote2 (s:String) (q:char) =
let isQuote = (fun c -> c = q)
let a = (s |> Seq.findIndex isQuote)+1
let b = ((s |> Seq.take(a) |> Seq.findIndex isQuote)-1)
s.Substring(a,b);
These will get the first instance of the quoted text anywhere in the string e.g "Hello [World]" -> "World"

Resources