문제

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.

도움이 되었습니까?

해결책

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.

다른 팁

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).

Trivial. Compile. Open in Reflector. Choose decompiler language to F#.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top