Created
December 12, 2013 04:12
-
-
Save jacotan/7923084 to your computer and use it in GitHub Desktop.
http://fssnip.net/3U をMS Excel向けCSVに特化 (Not Tested!)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// http://fssnip.net/3U をベースとするCSV出力モジュール。 | |
/// F#のSeqを拡張している。 | |
/// 元ネタではセパレータを選べたが、その機能を殺してMicrosoft Excel向けCSVに特化した。 | |
module Csv | |
open System.IO | |
open System.Text | |
open System.Text.RegularExpressions | |
open Microsoft.FSharp.Reflection | |
let csvEscape str = | |
// CSVのエスケープが必要な文字列表現を拾う正規表現 | |
let NeedCsvEscape str = Regex("(\"|'|,|\n|\r)",RegexOptions.Multiline).IsMatch(str) | |
let tempstr = str.ToString() | |
if (NeedCsvEscape tempstr) then | |
"\"" + tempstr.Replace("\"","\"\"") + "\"" | |
else tempstr | |
type Array = | |
static member join delimiter xs = | |
xs | |
|> Array.map (csvEscape) | |
|> String.concat delimiter | |
type Seq = | |
static member write (path:string) (data:seq<'a>): 'result = | |
use writer = new StreamWriter(path,false,Encoding.GetEncoding(932)) | |
data | |
|> Seq.iter writer.WriteLine | |
static member csv (headerMapping:string -> string) ( data:seq<'a>) = | |
let separator = "," | |
seq { | |
let dataType = typeof<'a> | |
let header = | |
match dataType with | |
| ty when FSharpType.IsRecord ty -> | |
FSharpType.GetRecordFields dataType | |
|> Array.map (fun info -> headerMapping info.Name) | |
| ty when FSharpType.IsTuple ty -> | |
FSharpType.GetTupleElements dataType | |
|> Array.mapi (fun idx info -> headerMapping(string idx) ) | |
| _ -> dataType.GetProperties() | |
|> Array.map (fun info -> headerMapping info.Name) | |
yield header |> Array.join separator | |
let lines = | |
match dataType with | |
| ty when FSharpType.IsRecord ty -> | |
data |> Seq.map FSharpValue.GetRecordFields | |
| ty when FSharpType.IsTuple ty -> | |
data |> Seq.map FSharpValue.GetTupleFields | |
| _ -> | |
let props = dataType.GetProperties() | |
data |> Seq.map ( fun line -> | |
props |> Array.map ( fun prop -> | |
prop.GetValue(line, null) )) | |
yield! lines |> Seq.map (Array.join separator) | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment