Reputation: 57
I found a quick project I thought would be perfect for learning F#. However I just cannot wrap my brain around it for some reason. After hours of tutorials and even some movies I still just... don't get it.
So I wanted to start versioning our stored procedures at work using Enterprise Manager "Generate Scripts" and wanted to blank out the script date. I gave up and did it in C# but now I'm REALLY curious and am hoping for some insight.
I am not completely empty handed, here is my C# code:
string path = @"C:\Subversion\CompanyName\SQL\DBName";
string fileSpec = "*.sql";
string pattern = @"Script Date: \d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}";
string replace = "Script Date: ";
foreach (var file in Directory.EnumerateFiles(path, fileSpec))
{
string content = File.ReadAllText(file);
content = Regex.Replace(content, pattern, replace);
File.WriteAllText(file, content, Encoding.Unicode);
}
I am guessing there is some cool looking 2-3 line solution in F#... I'd love to see it.
Thx for the tips! I have updated it to match what is being done below to make the visual comparison potentially more enlightening. Also great comments below.
Upvotes: 3
Views: 646
Reputation: 243041
Pretty much all you need to do is to replace type name in variable declarations (where you could write var
in C#) with the let
keyword, remove all semicolons and curly braces and replace foreach
with
for file in files do
. You're also using some namespaces, so in F#, you need something like:
open System.IO
open System.Text.RegularExpressions
You're using one mutable variable (content
), but you don't really need to mutate it. You can just use a different variable (such as newContent
) to store the result of replacement. So, the middle part will be:
let content = File.ReadAllText(file) // No need for a stream reader here!
let pattern = @"Script Date: \d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}"
let replace = "Script Date: "
let newContent = Regex.Replace(content, pattern, replace)
You could also use the same variable name, which means that you're declaring a new (immutable) variable that hides the previous one in the rest of the scope (see this SO answer for more information)
I would also change the last bit (even in C#!) to close the stream even if an exception occurs. In C#, you would use using
. To write the same thing in F#, you can use the use
keyword:
use fileStream = new FileStream(file, FileMode.Truncate, FileAccess.Write, FileShare.None)
use writer = new StreamWriter(fileStream, Encoding.Unicode)
writer.Write(content)
writer.Flush()
The use
keyword ensures that the object is disposed (closed) when it goes out of scope - that is, at the end of the for
loop iteration (in this case).
Upvotes: 6
Reputation: 62975
let path = @"C:\Subversion\CompanyName\SQL\DBName"
let fileSpec = "*.sql"
let pattern = @"Script Date: \d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}"
let replace = "Script Date: "
Directory.EnumerateFiles (path, fileSpec)
|> Seq.iter (fun file ->
let content = Regex.Replace (File.ReadAllText file, pattern, replace)
File.WriteAllText (file, content, Encoding.Unicode))
Note that your C# code is (EDIT: was) also far more verbose than necessary.
Upvotes: 11
Reputation: 5215
Trivial. Compile. Open in Reflector. Choose decompiler language to F#.
Upvotes: 1