F# Remove/Replace char in a specific string index - string

I want to remove a char in a string. but not all the elements of that char in a string. example. i want "|red|red|red|red|" to turn into "red|red|red|red" So I want to create a function that checks if the first and last index of a string is a certain char and remove it if its the case.
so far i have come up with something like this:
let rec inputFormatter (s : string) : string =
match s.[1] with
|'|'|','|'.'|'-' -> // something that replaces the char with "" in the string s
(inputFormatter s)
|_ -> match s.[(String.length s)] with
|"|"|","|"."|"-" -> // same as above.
(inputFormatter s)
|_ -> s
Can anyone help me figure out what i could write in my function? Ofcourse you are also welcome to come up with an etirely different function if you find that more conveniet.
thanks in advance!

let replace elem (str:string) =
let len = String.length str
if str.[0] = elem && str.[len-1] = elem then str.[1..len-2]
else str
Usage:
replace '|' "|red|red|red|red|"
// val it : string = "red|red|red|red"
And here's a version working with string instead of char:
let replace elem (str:string) =
let lens = String.length str
let lene = String.length elem
if lene <= lens && str.[0..lene-1] = elem && str.[lens-lene..lens-1] = elem then str.[lene..lens-lene-1]
else str
UPDATE
As Mark suggested a better option is re-using Trim
let replace (elem:string) (str:string) = str.Trim(elem.ToCharArray())

I didn't end up using Gutavo's fix but it was him that inspired me to fix my own function!
let rec theButcher (s : string) : string =
match s.[0] with
|'|'|','|'.'|'-'|' ' -> (theButcher s.[1..])
|_ -> match s.[(String.length s)-1] with
|'|'|','|'.'|'-'|' ' -> (theButcher s.[0..((String.length s)-2)])
|_ -> s

Related

Haskell: Replace a subString in a String without Data.List package

I'm very new in Haskell and I want to know how I can replace a predetermined word in a String by another word. This is my code so far, I know I can't do this for now:
treat :: String -> String
treat text = text
main::IO()
main = do argv <- getArgs
texte <- readFile "intputText"
print (separation text)
print ( treat text )
separation :: String -> [String]
separation [] = [""]
separation (c:cs) | c == "\Graph" = "Graphic : " : rest
| c == '}' = "" : rest
| c == '{' = "" : rest
| otherwise = (c : head rest) : tail rest
where rest = separation cs
So basically I know I can't put a String in the first c == "\Graph" so I want to know
how I can basically replace every word "\Graph" in my String text by "Graphic".
I want to be able to do that without importing any package.
If anyone can help me out I'd really appreciate it.
Thank you very much!
replace :: String -> String -> String-> String
replace [] token repl = []
replace str#(s:ss) token#(t:tx) repl
-- check if first char of string equal to first char of token
| s == t = case validateToken token str of
Just list -> repl ++ replace list token repl
Nothing -> s : replace ss token repl
-- if not equal then continue recursion step
| otherwise = s: replace ss token repl
where
-- validate if token matches the following chars of the string
-- returns Nothing if token is not matched
-- returns the remaining string after the token if token is matched
validateToken:: String -> String -> Maybe String
validateToken (a:as) [] = Nothing
validateToken [] list = Just list
validateToken (a:as) (x:xs)
| a == x = validateToken as xs
| otherwise = Nothing
example = replace "yourString" "token" "new"

F# - Remove duplicate characters after first in string

What I am trying to do is to remove duplicates of a specific given char in a string but letting the first char to remain. I.e:
let myStr = "hi. my .name."
//a function that gets a string and the element to be removed in the string
someFunc myStr "."
where someFunc returns the string showen as below:
"hi. my name"
It is easy to remove duplicates from a string, but is there a way to remove the duplicates but letting the first duplicated element remain in the string?
Here's one approach:
let keepFirst c s =
Seq.mapFold (fun k c' -> (c', k||c<>c'), k&&c<>c') true s
|> fst
|> Seq.filter snd
|> Seq.map fst
|> Array.ofSeq
|> System.String
let example = keepFirst '.' "hi. my .name."
let someFunc (str : string) c =
let parts = str.Split([| c |])
if Array.length parts > 1 then
seq {
yield Array.head parts
yield string c
yield! Array.tail parts
}
|> String.concat ""
else
str
Note that the character is given as char instead of a string.
let someFunc chr (str:string) =
let rec loop (a: char list) b = function
| [] -> a |> List.rev |> System.String.Concat
| h::t when h = chr -> if b then loop a b t
else loop (h::a) true t
| h::t -> loop (h::a) b t
loop [] false (str.ToCharArray() |> Array.toList)
Note that the character is given as char instead of a string.
Edit: Another way would be using regular expressions
open System.Text.RegularExpressions
let someOtherFunc c s =
let pat = Regex.Escape(c)
Regex.Replace(s, sprintf "(?<=%s.*)%s" pat pat, "")
Note that, in this case the character is given as string.
Edit 2:
let oneMoreFunc (c:char) (s:string) =
let pred = (<>) c
[ s |> Seq.takeWhile pred
seq [c]
s |> Seq.skipWhile pred |> Seq.filter pred ]
|> Seq.concat
|> System.String.Concat
When devising a function, think about gains from making its arguments generic. To pass state through the iteration, barring mutable variables, Seq.scan could be a weapon of choice. It folds into a tuple of new state and an option, then Seq.choose strips out the state and the unwanted elements.
In terms of functional building blocks, make it accept a predicate function 'a -> bool and let it return a function seq<'a> -> seq<'a>.
let filterDuplicates predicate =
Seq.scan (fun (flag, _) x ->
let p = predicate x in flag || p,
if flag && p then None else Some x ) (false, None)
>> Seq.choose snd
This can then easily reused to do other things as well, like 0 together with odd numbers.
filterDuplicates (fun i -> i % 2 = 0) [0..10]
// val it : seq<int> = seq [0; 1; 3; 5; ...]
Supplied with a call to the equality operator and fed into the constructor of System.String, you'll get near the signature you want, char -> seq<char> -> System.String.
let filterDuplicatesOfChar what s =
System.String(Array.ofSeq <| filterDuplicates ((=) what) s)
filterDuplicatesOfChar '.' "hi. my .name."
// val it : string = "hi. my name"

Function String Caml light

I need a function that take a string and a char , it slides the string and if it found the char return TRUE else FALSE.
This is my start point:
let rec check s a = match s with
"" -> false
| x::xs -> if x = a then true else check xs a ;;
I can’t use the library function of caml light (like index_char)
Thanks for help!
I will leave the explanation of how it works to you, this is my solution:
strobel#suse131:~> rlwrap camllight
> Caml Light version 0.75
let findchar c s =
let len = string_length s in
let rec f1 i s =
if i = len then false
else if s.[i]=c then true else f1 (succ i) s in
f1 0 s
;;
findchar : char -> string -> bool = <fun>
#let s = "this is the searched string";;
s : string = "this is the searched string"
#findchar `a` s;;
- : bool = true
#findchar `y` s;;
- : bool = false
Additional exercises:
could we leave out parameter s in the f1 definition?
how do we call the usage / occurence of len in the body of f1?

Haskell: Pig Latin

Question: The simple rule for translating into “Pig Latin” is to take a word that begins with a vowel and add "yay", while taking any word that be- gins with one or more consonants and transferring them to the back before appending "ay". For example, "able" becomes "ableyay" and "stripe" becomes "ipestray". Write a function that converts a string of letters into its Pig-Latin translation.
Implementation:
-- define function to detect vowel
isVowel :: Char -> Bool
isVowel c = elem c ['u','e','o','a','i']
-- define function Latin Pig
lp ::String -> String
lp str = if (isVowel (head str)) then do {str ++ "yay"}
else
do {
str ++ (head str)
tail str
lp str
}
Problem: So far I do not see any problem with my code (logic). Honestly this is my homework for an Intro to Haskell course. However the compiler gives me errors:
**Couldn't match expected type `t0 -> t1 -> t2 -> t3 -> [Char]'
with actual type `Char'
Expected type: [t0 -> t1 -> t2 -> t3 -> [Char]]
Actual type: String
In the first argument of `head', namely `str'
In the second argument of `(++)', namely
`(head str) tail str lp str'
Failed, modules loaded: none.**
What is wrong with my code?!
To begin, think about pattern matching.
Any not empty list can be define as x:xs, with,
x as head list
xs as tail list
then your code become,
-- define function Latin Pig
lp :: String -> String
lp [] = ""
lp (x:xs) = if (isVowel x) then str ++ "yay"
else ..... -- fill here
where str = (x:xs)
don't forget that the operator : is the constructor of list, for example,
'a':"bab" => "abab"
Keep in mind that a string is a list of char.
Furthermore, you can skip the where clause in the previous example, like this,
-- define function Latin Pig
lp :: String -> String
lp [] = ""
lp str#(x:xs) = if (isVowel x) then str ++ "yay"
else ..... -- fill here
Should be enough to help you.
Good luck
Here is another way of putting the pig latin rule:
if a word doesn't begin with a run of consonants, then the translation is the original word followed by "yay"
otherwise the translation is the rest of the word, followed by the initial run of consonants, followed by "ay"
This is easier to translate into Haskell.
(Actual Haskell code elided, as this is homework.)
You will find it helpful to combine your isVowel function with the break function from Data.List.
I'm not sure if it is part of your requirements to use recursion but here is my take on your task. You do not need to use the do monad to achieve what you want (unless that is an objective of the assignment?).
You might want to consider using pattern matching and guards instead of an if else block.
Also, like zurgl said, you can take advantage of matching the string like this: string#(x:xs) which will allow you to do work on the entire string while also using the head x and tail xs.
Note: All strings are lists.
Here is a quick example of what I suggested.
-- define function to detect vowel
isNotVowel :: Char -> Bool
isNotVowel c = notElem c ['u','e','o','a','i']
-- define function Latin Pig
lp :: String -> String
lp [] = []
lp p#(x:xs)
| not $ isNotVowel x = p++"yay"
| otherwise = let (constants, rest) = span isNotVowel p
in (rest++constants++"ay")
Have fun learning haskell!
Some nice resources for learning haskell:
Learn You A Haskell For Great Good
Real World Haskell
Kindly refer following code.
private static BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws IOException {
System.out.print("Enter sentence: ");
String sentence = getString();
String latin = pigLatinForSentence(sentence);
System.out.println(latin);
}
private static String pigLatinForSentence(String s) {
String latin = "";
int i = 0;
while (i < s.length()) {
while (i < s.length() && !isLetter(s.charAt(i))) {
latin = latin + s.charAt(i);
i++;
}
if (i >= s.length())
break;
int begin = i;
while (i < s.length() && isLetter(s.charAt(i))) {
i++;
}
int end = i;
latin = latin + pigWord(s.substring(begin, end));
}
return latin;
}
private static boolean isLetter(char c) {
return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'));
}
private static String pigWord(String word) {
int split = firstVowelInSentence(word);
return word.substring(split) + "-" + word.substring(0, split) + "ay";
}
private static int firstVowelInSentence(String word) {
word = word.toLowerCase();
for (int i = 0; i < word.length(); i++)
if (word.charAt(i) == 'a' || word.charAt(i) == 'e' || word.charAt(i) == 'i' || word.charAt(i) == 'o'
|| word.charAt(i) == 'u')
return i;
return 0;
}
private static String getString() throws IOException {
return buf.readLine();
}
Hope this solution help you learn more detail about pig latin.

How To Change List of Chars To String?

In F# I want to transform a list of chars into a string. Consider the following code:
let lChars = ['a';'b';'c']
If I simply do lChars.ToString, I get "['a';'b';'c']". I'm trying to get "abc". I realize I could probably do a List.reduce to get the effect I'm looking for but it seems like there should be some primitive built into the library to do this.
To give a little context to this, I'm doing some manipulation on individual characters in a string and when I'm done, I want to display the resulting string.
I've tried googling this and no joy that way. Do I need to just bite the bullet and build a List.reduce expression to do this transformation or is there some more elegant way to do this?
Have you tried
System.String.Concat(Array.ofList(lChars))
How many ways can you build a string in F#?
Here's another handful:
let chars = ['H';'e';'l';'l';'o';',';' ';'w';'o';'r';'l';'d';'!']
//Using an array builder
let hw1 = new string [|for c in chars -> c|]
//StringBuilder-Lisp-like approach
open System.Text
let hw2 =
string (List.fold (fun (sb:StringBuilder) (c:char) -> sb.Append(c))
(new StringBuilder())
chars)
//Continuation passing style
let hw3 =
let rec aux L k =
match L with
| [] -> k ""
| h::t -> aux t (fun rest -> k (string h + rest) )
aux chars id
Edit: timings may be interesting? I turned hw1..3 into functions and fed them a list of 500000 random characters:
hw1: 51ms
hw2: 16ms
hw3: er... long enough to grow a beard? I think it just ate all of my memory.
Didn't see this one here, so:
let stringFromCharList (cl : char list) =
String.concat "" <| List.map string cl
"" is just an empty string.
FSI output:
> stringFromCharList ['a'..'d'];;
val it : string = "abcd"
EDIT:
Didn't like this syntax coming back to this so here's a more canonically functional one:
['a'..'z'] |> List.map string |> List.reduce (+)
['a';'b';'c'] |> List.fold_left (fun acc c -> acc ^ (string c)) ""
Edited:
Here is yet another funny way to do your task:
type t =
| N
| S of string
static member Zero
with get() = N
static member (+) (a: t, b: t) =
match a,b with
| S a, S b -> S (a+b)
| N, _ -> b
| _, N -> a
let string_of_t = function
|N -> ""
|S s -> s
let t_of_char c = S (string c)
['a'; 'b'; 'c'] |> List.map t_of_char |> List.sum |> string_of_t
Sadly, just extending System.String with 'Zero' member does not allow to use List.sum with strings.
Edited (answer to Juilet):
Yes, you are right, left fold is slow. But i know more slow right fold :) :
#r "FSharp.PowerPack"
List.fold_right (String.make 1 >> (^)) ['a';'b';'c'] ""
and of course there is fast and simple:
new System.String(List.to_array ['1';'2';'3'])
And i used 'sprintf' seems to me easier:
let t = "Not what you might expect"
let r = [ for i in "aeiou" -> i]
let q = [for a in t do if not (List.exists (fun x -> x=a) r) then yield a]
let rec m = function [] -> "" | h::t -> (sprintf "%c" h) + (m t)
printfn "%A" (m q)
The following solution works for me:
let charList = ["H";"E";"L";"L";"O"]
let rec buildString list =
match list with
| [] -> ""
| head::tail -> head + (buildString tail)
let resultBuildString = buildString charList
[|'w'; 'i'; 'l'; 'l'|]
|> Array.map string
|> Array.reduce (+)
or as someone else posted:
System.String.Concat([|'w'; 'i'; 'l'; 'l'|])

Resources