fparsec to parse sequence of string - f#

I have an user input text like "abc,def,ghi". I want to parse it to get list of string as ["abc", "def"].
I tried
let str : Parser<_> = many1Chars (noneOf ",")
let listParser : Parser<_> = many (str);;
but it always give me the first item only ["abc"]. "Def" and others are not coming in result list

You're parsing up to the first comma, but not parsing the comma itself.
To parse a list of things separated by other things, use sepBy:
let comma = pstring ","
let listParser = sepBy str comma
If you need to parse "at least one", use sepBy1 instead.

Related

Split a string by an entire word, not just one character

I want to split a str by more than one character but I keep getting errors. Is this even possible? A brief search seems to imply it's not.
I want to do something like this:
let strspl = "test="
let spl : [String] = str.split(separator: Character(strspl), maxSplits: 1).map(String.init)
Error is:
Can't form a Character from a String containing more than one extended grapheme cluster
You can use components(separatedBy:) method to get an array of string by separating a string with a string separator
var str = "another test= long test"
let strspl = "test="
let spl : [String] = str.components(separatedBy: strspl)
print(spl)
["another ", " long test"]

Formatting string with %28# in Swift

I am trying to print a string in formatted like " FOO"
in Swift 4. I can do it with chars but I can't do it with a string object.
I tried:
let a = String(format: "%28c", 0x31)
print (a)
// prints " 1"
But this only works with chars, not with strings.
How can I get the same result with strings?

Swift: how to suppress interpretation of special characters and provide string literal

The goal is to serialize a Swift object by converting it to a JSON object then converting the JSON object into a JSON string that can be passed over the wire and decoded on the other side.
The problem is producing a valid JSON string.
Newlines must be escaped in a JSON string, but Swift interprets special characters in the escaped string instead of treating the string as a literal.
For example:
let a = "foobar\nhello\nworld"
let escapedString = a.replacingOccurrences(of: "\n", with: "\\n")
print(escapedString)
What gets printed is foobar\nhello\nworld instead of the desired foobar\\nhello\\nworld.
How do you tell Swift to treat a string as a literal and not to interpret special characters within?
UPDATE
As OOPer points out, using debugPrint shows the \\n characters remaining intact.
However, when paired with evaluateJavaScript in WKWebView, the \\n characters are turned into \n, which is the root issue. For example:
let script = "\(callback)(\'\(escapedString)\')"
webView!.evaluateJavaScript(script) { (object: Any?, error: Error?) -> Void in
print("Done invoking \(callback)")
}
There is no unescaped string syntax like in javascript template literals which is probably what you are looking for; maybe they will add it in the future. Unfortunately you therefore have to escape each back slash which sometimes looks very scray, as in your example.
//This is the same as `foobar\nhello\nworld` where each char is a literal
let a = "foobar\\nhello\\nworld"
let escapedString = a.replacingOccurrences(of: "\\n", with: "\\\\n")
//This outputs `foobar\\nhello\\nworld`
print(escapedString)
Maybe you are just mistaking to interpret the output from print.
When you get foobar\nhello\nworld from print(escapedString), escapedString contains 20 characters -- f o o b a r \ n h e l l o \ n w o r l d.
This is a valid JSON string when enclosed between "s.
If you want to check the escaped result in String-literal-like notation, you can use debugPrint:
let a = "foobar\nhello\nworld"
let escapedString = a.replacingOccurrences(of: "\n", with: "\\n")
print(escapedString) //->foobar\nhello\nworld
debugPrint(escapedString) //->"foobar\\nhello\\nworld"
For UPDATE
When using with evaluateJavaScript, you'd better think what is the right code as JavaScript, if you want to represent a JSON escaped string in JavaScript, you would write in .js file (or in <script>...</script>):
someFunc('foobar\\nhello\\nworld');
So, you may need to write something like this:
let a = "foobar\nhello\nworld"
let escapedForJSON = a.replacingOccurrences(of: "\n", with: "\\n")
//In actual code, you may need a little more...
let escapedForJavaScriptString = escapedForJSON.replacingOccurrences(of: "\\", with: "\\\\")
let script = "\(callback)(\'\(escapedForJavaScriptString)\')"
webView!.evaluateJavaScript(script) { (object: Any?, error: Error?) -> Void in
print("Done invoking \(callback)")
}

fparsec parsing key value pairs with different data types

I'm trying to write a parser which can parse key value pairs which can vary on the value data type.
KEY1:1,2,3
KEY2:abc
KEY3:123
With the following code
open FParsec
type UserState = unit
type Parser<'t> = Parser<'t,UserState>
let str s = pstring s
let str_ws s = str s .>> spaces
let stringLiteral : Parser<_> = manyChars (noneOf "\">")
let numList : Parser<_> = sepBy1 (pint32) (str ",")
let parseHeader inner header = str header >>. str ":" >>. inner
let parseKvps =
let strHeader header = parseHeader stringLiteral header .>> newline
let numListHeader header = parseHeader numList header .>> newline
let numHeader header = parseHeader pint32 header .>> newline
let rest = parse {
let! key1 = numListHeader "KEY1"
let! key2 = strHeader "KEY2"
let! key3 = numHeader "KEY3"
return key1,key2,key3
}
rest
let kvps = "KEY1:1,2,3\nKEY2:abc\nKEY3:123"
run parseKvps kvps
Above gives the following error:
val it : ParserResult<(int32 list * string * int32),unit> =
Failure:
Error in Ln: 3 Col: 9
KEY3:123
^
Note: The error occurred at the end of the input stream.
Expecting: any char not in ‘">’ or newline
I think this has something to do with the numList parser because taking the first key out works as expected.
Appreciate any help! Thanks in advance!
The third parser fails because FParsec did not find a required \n at the end.
There are several options to fix the problem:
Make your data valid by adding \n to the stream:
let kvps = "KEY1:1,2,3\nKEY2:abc\nKEY3:123\n"
Downside: modifying a source stream is only good for testing, not for the real app.
Make .>> newline optional:
.>> (optional newline)
Downside: It may lead to errors when two keys at the same source line are attempted to parse.
Try using eof as a possible alternative to newline
Also, a side note. Your code seems to be very hard to support. Think what happens if the keys occur in a wrong order in the source string, or a new key needs to be added over the course of your app development.
Check this and this answers for more details.

How to use Lua gsub to remove '<!--more--> correctly?

I have a string that might contains '<!--more-->' and I am trying to remove it by using this code
local str = string.gsub (string, "<!--more-->", "")
but it doesn't work. The string still contains it.
I try with this
local str = string.gsub (string, "[<!--more-->]", "")
but it has an 'e' left.
The - character is special in patterns. You need to escape it:
local str = string.gsub (string, "<!%-%-more%-%->", "")

Resources