commit
cdeb78d3c0
|
@ -1,5 +1,5 @@
|
|||
language: objective-c
|
||||
osx_image: xcode7.3
|
||||
osx_image: xcode8
|
||||
env:
|
||||
- LC_CTYPE=en_US.UTF-8
|
||||
git:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = 'CSV.swift'
|
||||
s.version = '0.3.1'
|
||||
s.version = '1.0.0'
|
||||
s.license = 'MIT'
|
||||
s.summary = 'CSV reading library written in Swift.'
|
||||
s.homepage = 'https://github.com/yaslab/CSV.swift'
|
||||
|
|
|
@ -396,12 +396,15 @@
|
|||
TargetAttributes = {
|
||||
0E7E8C801D0BC7BB0057A1C1 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
0E7E8C8A1D0BC7BB0057A1C1 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
0E7E8CB41D0BC98B0057A1C1 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
0E7E8CC51D0BCA2A0057A1C1 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
|
@ -413,9 +416,11 @@
|
|||
};
|
||||
0E7E8CE71D0BCD0B0057A1C1 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
0E7E8CF01D0BCD0B0057A1C1 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -650,7 +655,6 @@
|
|||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 2.3;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
VERSION_INFO_PREFIX = "";
|
||||
|
@ -693,7 +697,6 @@
|
|||
MACOSX_DEPLOYMENT_TARGET = 10.9;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_VERSION = 2.3;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
|
@ -715,6 +718,7 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = net.yaslab.CSV;
|
||||
PRODUCT_NAME = CSV;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -733,6 +737,7 @@
|
|||
PRODUCT_NAME = CSV;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -743,6 +748,7 @@
|
|||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-iOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -754,6 +760,7 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-iOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -772,6 +779,7 @@
|
|||
PRODUCT_NAME = CSV;
|
||||
SDKROOT = watchos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = 4;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
};
|
||||
|
@ -793,6 +801,7 @@
|
|||
SDKROOT = watchos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = 4;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
};
|
||||
|
@ -816,6 +825,7 @@
|
|||
PRODUCT_NAME = CSV;
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -838,6 +848,7 @@
|
|||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -852,6 +863,7 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-OSX";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -867,6 +879,7 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -884,6 +897,7 @@
|
|||
PRODUCT_NAME = CSV;
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
};
|
||||
|
@ -904,6 +918,7 @@
|
|||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
};
|
||||
|
@ -917,6 +932,7 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-tvOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
SWIFT_VERSION = 3.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.2;
|
||||
};
|
||||
name = Debug;
|
||||
|
@ -930,6 +946,7 @@
|
|||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.2;
|
||||
};
|
||||
name = Release;
|
||||
|
|
|
@ -75,13 +75,13 @@ let csv = try! CSV(
|
|||
### CocoaPods
|
||||
|
||||
```ruby
|
||||
pod 'CSV.swift', '~> 0.3'
|
||||
pod 'CSV.swift', '~> 1.0'
|
||||
```
|
||||
|
||||
### Carthage
|
||||
|
||||
```
|
||||
github "yaslab/CSV.swift" ~> 0.3
|
||||
github "yaslab/CSV.swift" ~> 1.0
|
||||
```
|
||||
|
||||
### Swift Package Manager
|
||||
|
@ -92,7 +92,7 @@ import PackageDescription
|
|||
let package = Package(
|
||||
name: "PackageName",
|
||||
dependencies: [
|
||||
.Package(url: "https://github.com/yaslab/CSV.swift", majorVersion: 0, minor: 3)
|
||||
.Package(url: "https://github.com/yaslab/CSV.swift", majorVersion: 1, minor: 0)
|
||||
]
|
||||
)
|
||||
```
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
// Copyright © 2016 yaslab. All rights reserved.
|
||||
//
|
||||
|
||||
internal struct AnyIterator<T>: GeneratorType {
|
||||
internal struct AnyIterator<T>: IteratorProtocol {
|
||||
|
||||
private var _base_next: (() -> T?)
|
||||
|
||||
internal init<U: GeneratorType where U.Element == T>(base: U) {
|
||||
internal init<U: IteratorProtocol>(base: U) where U.Element == T {
|
||||
var base = base
|
||||
_base_next = { base.next() }
|
||||
}
|
||||
|
|
|
@ -14,26 +14,26 @@ internal let utf16LittleEndianBOM: [UInt8] = [0xff, 0xfe]
|
|||
internal let utf32BigEndianBOM: [UInt8] = [0x00, 0x00, 0xfe, 0xff]
|
||||
internal let utf32LittleEndianBOM: [UInt8] = [0xff, 0xfe, 0x00, 0x00]
|
||||
|
||||
private func readBOM(buffer buffer: UnsafePointer<UInt8>, length: Int) -> (Endian, Int)? {
|
||||
private func readBOM(buffer: UnsafePointer<UInt8>, length: Int) -> (Endian, Int)? {
|
||||
if length >= 4 {
|
||||
if memcmp(buffer, utf32BigEndianBOM, 4) == 0 {
|
||||
return (.Big, 4)
|
||||
return (.big, 4)
|
||||
}
|
||||
if memcmp(buffer, utf32LittleEndianBOM, 4) == 0 {
|
||||
return (.Little, 4)
|
||||
return (.little, 4)
|
||||
}
|
||||
}
|
||||
if length >= 3 {
|
||||
if memcmp(buffer, utf8BOM, 3) == 0 {
|
||||
return (.Unknown, 3)
|
||||
return (.unknown, 3)
|
||||
}
|
||||
}
|
||||
if length >= 2 {
|
||||
if memcmp(buffer, utf16BigEndianBOM, 2) == 0 {
|
||||
return (.Big, 2)
|
||||
return (.big, 2)
|
||||
}
|
||||
if memcmp(buffer, utf16LittleEndianBOM, 2) == 0 {
|
||||
return (.Little, 2)
|
||||
return (.little, 2)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -41,30 +41,30 @@ private func readBOM(buffer buffer: UnsafePointer<UInt8>, length: Int) -> (Endia
|
|||
|
||||
internal class BinaryReader {
|
||||
|
||||
private let stream: NSInputStream
|
||||
private let stream: InputStream
|
||||
private let endian: Endian
|
||||
private let closeOnDeinit: Bool
|
||||
|
||||
private var buffer = [UInt8](count: 4, repeatedValue: 0)
|
||||
private var buffer = [UInt8](repeating: 0, count: 4)
|
||||
|
||||
private var tempBuffer = [UInt8](count: 4, repeatedValue: 0)
|
||||
private var tempBuffer = [UInt8](repeating: 0, count: 4)
|
||||
private let tempBufferSize = 4
|
||||
private var tempBufferOffset = 0
|
||||
|
||||
internal init(stream: NSInputStream, endian: Endian = .Unknown, closeOnDeinit: Bool = true) throws {
|
||||
internal init(stream: InputStream, endian: Endian = .unknown, closeOnDeinit: Bool = true) throws {
|
||||
var endian = endian
|
||||
|
||||
if stream.streamStatus == .NotOpen {
|
||||
if stream.streamStatus == .notOpen {
|
||||
stream.open()
|
||||
}
|
||||
if stream.streamStatus != .Open {
|
||||
throw CSVError.CannotOpenFile
|
||||
if stream.streamStatus != .open {
|
||||
throw CSVError.cannotOpenFile
|
||||
}
|
||||
|
||||
let readCount = stream.read(&tempBuffer, maxLength: tempBufferSize)
|
||||
if let (e, l) = readBOM(buffer: &tempBuffer, length: readCount) {
|
||||
if endian != .Unknown && endian != e {
|
||||
throw CSVError.StringEndianMismatch
|
||||
if endian != .unknown && endian != e {
|
||||
throw CSVError.stringEndianMismatch
|
||||
}
|
||||
endian = e
|
||||
tempBufferOffset = l
|
||||
|
@ -76,7 +76,7 @@ internal class BinaryReader {
|
|||
}
|
||||
|
||||
deinit {
|
||||
if closeOnDeinit && stream.streamStatus != .Closed {
|
||||
if closeOnDeinit && stream.streamStatus != .closed {
|
||||
stream.close()
|
||||
}
|
||||
}
|
||||
|
@ -85,9 +85,9 @@ internal class BinaryReader {
|
|||
return stream.hasBytesAvailable
|
||||
}
|
||||
|
||||
private func readStream(buffer: UnsafeMutablePointer<UInt8>, maxLength: Int) throws -> Int {
|
||||
if stream.streamStatus != .Open {
|
||||
throw CSVError.CannotReadFile
|
||||
private func readStream(_ buffer: UnsafeMutablePointer<UInt8>, maxLength: Int) throws -> Int {
|
||||
if stream.streamStatus != .open {
|
||||
throw CSVError.cannotReadFile
|
||||
}
|
||||
|
||||
var i = 0
|
||||
|
@ -106,10 +106,10 @@ internal class BinaryReader {
|
|||
let bufferSize = 1
|
||||
let length = try readStream(&buffer, maxLength: bufferSize)
|
||||
if length < 0 {
|
||||
throw CSVError.StreamErrorHasOccurred(error: stream.streamError!)
|
||||
throw CSVError.streamErrorHasOccurred(error: stream.streamError!)
|
||||
}
|
||||
if length != bufferSize {
|
||||
throw CSVError.CannotReadFile
|
||||
throw CSVError.cannotReadFile
|
||||
}
|
||||
return buffer[0]
|
||||
}
|
||||
|
@ -118,19 +118,20 @@ internal class BinaryReader {
|
|||
let bufferSize = 2
|
||||
let length = try readStream(&buffer, maxLength: bufferSize)
|
||||
if length < 0 {
|
||||
throw CSVError.StreamErrorHasOccurred(error: stream.streamError!)
|
||||
throw CSVError.streamErrorHasOccurred(error: stream.streamError!)
|
||||
}
|
||||
if length != bufferSize {
|
||||
throw CSVError.StringEncodingMismatch
|
||||
throw CSVError.stringEncodingMismatch
|
||||
}
|
||||
let tmp = UnsafeMutablePointer<UInt16>(buffer)
|
||||
return try UnsafePointer(buffer).withMemoryRebound(to: UInt16.self, capacity: 1) {
|
||||
switch endian {
|
||||
case .Big:
|
||||
return CFSwapInt16BigToHost(tmp[0])
|
||||
case .Little:
|
||||
return CFSwapInt16LittleToHost(tmp[0])
|
||||
case .big:
|
||||
return CFSwapInt16BigToHost($0[0])
|
||||
case .little:
|
||||
return CFSwapInt16LittleToHost($0[0])
|
||||
default:
|
||||
throw CSVError.StringEndianMismatch
|
||||
throw CSVError.stringEndianMismatch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,19 +139,20 @@ internal class BinaryReader {
|
|||
let bufferSize = 4
|
||||
let length = try readStream(&buffer, maxLength: bufferSize)
|
||||
if length < 0 {
|
||||
throw CSVError.StreamErrorHasOccurred(error: stream.streamError!)
|
||||
throw CSVError.streamErrorHasOccurred(error: stream.streamError!)
|
||||
}
|
||||
if length != 4 {
|
||||
throw CSVError.StringEncodingMismatch
|
||||
throw CSVError.stringEncodingMismatch
|
||||
}
|
||||
let tmp = UnsafeMutablePointer<UInt32>(buffer)
|
||||
return try UnsafePointer(buffer).withMemoryRebound(to: UInt32.self, capacity: 1) {
|
||||
switch endian {
|
||||
case .Big:
|
||||
return CFSwapInt32BigToHost(tmp[0])
|
||||
case .Little:
|
||||
return CFSwapInt32LittleToHost(tmp[0])
|
||||
case .big:
|
||||
return CFSwapInt32BigToHost($0[0])
|
||||
case .little:
|
||||
return CFSwapInt32LittleToHost($0[0])
|
||||
default:
|
||||
throw CSVError.StringEndianMismatch
|
||||
throw CSVError.stringEndianMismatch
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,11 +160,11 @@ internal class BinaryReader {
|
|||
|
||||
extension BinaryReader {
|
||||
|
||||
internal struct UInt8Iterator: SequenceType, GeneratorType {
|
||||
internal struct UInt8Iterator: Sequence, IteratorProtocol {
|
||||
|
||||
private let reader: BinaryReader
|
||||
|
||||
private init(reader: BinaryReader) {
|
||||
fileprivate init(reader: BinaryReader) {
|
||||
self.reader = reader
|
||||
}
|
||||
|
||||
|
@ -188,11 +190,11 @@ extension BinaryReader {
|
|||
|
||||
extension BinaryReader {
|
||||
|
||||
internal struct UInt16Iterator: SequenceType, GeneratorType {
|
||||
internal struct UInt16Iterator: Sequence, IteratorProtocol {
|
||||
|
||||
private let reader: BinaryReader
|
||||
|
||||
private init(reader: BinaryReader) {
|
||||
fileprivate init(reader: BinaryReader) {
|
||||
self.reader = reader
|
||||
}
|
||||
|
||||
|
@ -218,11 +220,11 @@ extension BinaryReader {
|
|||
|
||||
extension BinaryReader {
|
||||
|
||||
internal struct UInt32Iterator: SequenceType, GeneratorType {
|
||||
internal struct UInt32Iterator: Sequence, IteratorProtocol {
|
||||
|
||||
private let reader: BinaryReader
|
||||
|
||||
private init(reader: BinaryReader) {
|
||||
fileprivate init(reader: BinaryReader) {
|
||||
self.reader = reader
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import Foundation
|
|||
extension CSV {
|
||||
|
||||
public init(
|
||||
stream: NSInputStream,
|
||||
stream: InputStream,
|
||||
hasHeaderRow: Bool = defaultHasHeaderRow,
|
||||
delimiter: UnicodeScalar = defaultDelimiter)
|
||||
throws
|
||||
|
@ -29,7 +29,7 @@ extension CSV {
|
|||
delimiter: UnicodeScalar = defaultDelimiter)
|
||||
throws
|
||||
{
|
||||
let iterator = string.unicodeScalars.generate()
|
||||
let iterator = string.unicodeScalars.makeIterator()
|
||||
try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ extension CSV {
|
|||
guard let headerRow = headerRow, let currentRow = currentRow else {
|
||||
return nil
|
||||
}
|
||||
guard let index = headerRow.indexOf(key) else {
|
||||
guard let index = headerRow.index(of: key) else {
|
||||
return nil
|
||||
}
|
||||
if index >= currentRow.count {
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
private let LF = "\n".unicodeScalars.first!
|
||||
private let CR = "\r".unicodeScalars.first!
|
||||
private let DQUOTE = "\"".unicodeScalars.first!
|
||||
private let LF = UnicodeScalar("\n")!
|
||||
private let CR = UnicodeScalar("\r")!
|
||||
private let DQUOTE = UnicodeScalar("\"")!
|
||||
|
||||
internal let defaultHasHeaderRow = false
|
||||
internal let defaultDelimiter = ",".unicodeScalars.first!
|
||||
internal let defaultDelimiter = UnicodeScalar(",")!
|
||||
|
||||
public struct CSV: GeneratorType, SequenceType {
|
||||
public struct CSV: IteratorProtocol, Sequence {
|
||||
|
||||
private var iterator: AnyIterator<UnicodeScalar>
|
||||
private let delimiter: UnicodeScalar
|
||||
|
@ -28,18 +28,18 @@ public struct CSV: GeneratorType, SequenceType {
|
|||
public var headerRow: [String]? { return _headerRow }
|
||||
private var _headerRow: [String]? = nil
|
||||
|
||||
internal init<T: GeneratorType where T.Element == UnicodeScalar>(
|
||||
internal init<T: IteratorProtocol>(
|
||||
iterator: T,
|
||||
hasHeaderRow: Bool,
|
||||
delimiter: UnicodeScalar)
|
||||
throws
|
||||
throws where T.Element == UnicodeScalar
|
||||
{
|
||||
self.iterator = AnyIterator(base: iterator)
|
||||
self.delimiter = delimiter
|
||||
|
||||
if hasHeaderRow {
|
||||
guard let headerRow = next() else {
|
||||
throw CSVError.CannotReadHeaderRow
|
||||
throw CSVError.cannotReadHeaderRow
|
||||
}
|
||||
_headerRow = headerRow
|
||||
}
|
||||
|
@ -51,14 +51,15 @@ public struct CSV: GeneratorType, SequenceType {
|
|||
/// - parameter codecType: A `UnicodeCodec` type for `stream`.
|
||||
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
|
||||
/// - parameter delimiter: Default: `","`.
|
||||
public init<T: UnicodeCodecType where T.CodeUnit == UInt8>(
|
||||
stream: NSInputStream,
|
||||
public init<T: UnicodeCodec>(
|
||||
stream: InputStream,
|
||||
codecType: T.Type,
|
||||
hasHeaderRow: Bool = defaultHasHeaderRow,
|
||||
delimiter: UnicodeScalar = defaultDelimiter)
|
||||
throws
|
||||
where T.CodeUnit == UInt8
|
||||
{
|
||||
let reader = try BinaryReader(stream: stream, endian: .Unknown, closeOnDeinit: true)
|
||||
let reader = try BinaryReader(stream: stream, endian: .unknown, closeOnDeinit: true)
|
||||
let iterator = UnicodeIterator(input: reader.makeUInt8Iterator(), inputEncodingType: codecType)
|
||||
try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
|
||||
}
|
||||
|
@ -70,13 +71,14 @@ public struct CSV: GeneratorType, SequenceType {
|
|||
/// - parameter endian: Endian to use when reading a stream. Default: `.big`.
|
||||
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
|
||||
/// - parameter delimiter: Default: `","`.
|
||||
public init<T: UnicodeCodecType where T.CodeUnit == UInt16>(
|
||||
stream: NSInputStream,
|
||||
public init<T: UnicodeCodec>(
|
||||
stream: InputStream,
|
||||
codecType: T.Type,
|
||||
endian: Endian = .Big,
|
||||
endian: Endian = .big,
|
||||
hasHeaderRow: Bool = defaultHasHeaderRow,
|
||||
delimiter: UnicodeScalar = defaultDelimiter)
|
||||
throws
|
||||
where T.CodeUnit == UInt16
|
||||
{
|
||||
let reader = try BinaryReader(stream: stream, endian: endian, closeOnDeinit: true)
|
||||
let iterator = UnicodeIterator(input: reader.makeUInt16Iterator(), inputEncodingType: codecType)
|
||||
|
@ -90,13 +92,14 @@ public struct CSV: GeneratorType, SequenceType {
|
|||
/// - parameter endian: Endian to use when reading a stream. Default: `.big`.
|
||||
/// - parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
|
||||
/// - parameter delimiter: Default: `","`.
|
||||
public init<T: UnicodeCodecType where T.CodeUnit == UInt32>(
|
||||
stream: NSInputStream,
|
||||
public init<T: UnicodeCodec>(
|
||||
stream: InputStream,
|
||||
codecType: T.Type,
|
||||
endian: Endian = .Big,
|
||||
endian: Endian = .big,
|
||||
hasHeaderRow: Bool = defaultHasHeaderRow,
|
||||
delimiter: UnicodeScalar = defaultDelimiter)
|
||||
throws
|
||||
where T.CodeUnit == UInt32
|
||||
{
|
||||
let reader = try BinaryReader(stream: stream, endian: endian, closeOnDeinit: true)
|
||||
let iterator = UnicodeIterator(input: reader.makeUInt32Iterator(), inputEncodingType: codecType)
|
||||
|
@ -178,7 +181,7 @@ public struct CSV: GeneratorType, SequenceType {
|
|||
return row
|
||||
}
|
||||
|
||||
internal mutating func readField(quoted quoted: Bool) -> (String, Bool) {
|
||||
internal mutating func readField(quoted: Bool) -> (String, Bool) {
|
||||
var field = ""
|
||||
|
||||
var next = moveNext()
|
||||
|
@ -202,15 +205,15 @@ public struct CSV: GeneratorType, SequenceType {
|
|||
}
|
||||
else if cNext == DQUOTE {
|
||||
// ESC
|
||||
field.append(DQUOTE)
|
||||
field.append(String(DQUOTE))
|
||||
}
|
||||
else {
|
||||
// ERROR??
|
||||
field.append(c)
|
||||
field.append(String(c))
|
||||
}
|
||||
}
|
||||
else {
|
||||
field.append(c)
|
||||
field.append(String(c))
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -229,7 +232,7 @@ public struct CSV: GeneratorType, SequenceType {
|
|||
return (field, false)
|
||||
}
|
||||
else {
|
||||
field.append(c)
|
||||
field.append(String(c))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
public enum CSVError: ErrorType {
|
||||
case CannotOpenFile
|
||||
case CannotReadFile
|
||||
case StreamErrorHasOccurred(error: NSError)
|
||||
case CannotReadHeaderRow
|
||||
case StringEncodingMismatch
|
||||
case StringEndianMismatch
|
||||
public enum CSVError: Error {
|
||||
case cannotOpenFile
|
||||
case cannotReadFile
|
||||
case streamErrorHasOccurred(error: Error)
|
||||
case cannotReadHeaderRow
|
||||
case stringEncodingMismatch
|
||||
case stringEndianMismatch
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//
|
||||
|
||||
public enum Endian {
|
||||
case Big
|
||||
case Little
|
||||
case Unknown
|
||||
case big
|
||||
case little
|
||||
case unknown
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.3.1</string>
|
||||
<string>1.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
//
|
||||
|
||||
internal struct UnicodeIterator<
|
||||
Input: GeneratorType,
|
||||
InputEncoding: UnicodeCodecType
|
||||
where InputEncoding.CodeUnit == Input.Element>
|
||||
: GeneratorType {
|
||||
Input: IteratorProtocol,
|
||||
InputEncoding: UnicodeCodec>
|
||||
: IteratorProtocol
|
||||
where InputEncoding.CodeUnit == Input.Element {
|
||||
|
||||
private var input: Input
|
||||
private var inputEncoding: InputEncoding
|
||||
|
@ -22,9 +22,9 @@ internal struct UnicodeIterator<
|
|||
|
||||
internal mutating func next() -> UnicodeScalar? {
|
||||
switch inputEncoding.decode(&input) {
|
||||
case .Result(let c): return c
|
||||
case .EmptyInput: return nil
|
||||
case .Error: return nil
|
||||
case .scalarValue(let c): return c
|
||||
case .emptyInput: return nil
|
||||
case .error: return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import XCTest
|
||||
@testable import CSV
|
||||
|
||||
|
@ -161,11 +162,11 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testUTF8WithBOM() {
|
||||
let csvString = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF8StringEncoding
|
||||
var mutableData = NSMutableData()
|
||||
mutableData.appendBytes(utf8BOM, length: utf8BOM.count)
|
||||
mutableData.appendData(csvString.dataUsingEncoding(encoding)!)
|
||||
let stream = NSInputStream(data: mutableData)
|
||||
let encoding = String.Encoding.utf8
|
||||
var mutableData = Data()
|
||||
mutableData.append(utf8BOM, count: utf8BOM.count)
|
||||
mutableData.append(csvString.data(using: encoding)!)
|
||||
let stream = InputStream(data: mutableData)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF8.self)
|
||||
let records = getRecords(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
|
@ -174,11 +175,11 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testUTF16WithNativeEndianBOM() {
|
||||
let csvString = "abab,,cdcd,efef\r\nzxcv,😆asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF16StringEncoding
|
||||
var mutableData = NSMutableData()
|
||||
mutableData.appendData(csvString.dataUsingEncoding(encoding)!)
|
||||
let stream = NSInputStream(data: mutableData)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .Unknown)
|
||||
let encoding = String.Encoding.utf16
|
||||
var mutableData = Data()
|
||||
mutableData.append(csvString.data(using: encoding)!)
|
||||
let stream = InputStream(data: mutableData as Data)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .unknown)
|
||||
let records = getRecords(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "😆asdf", "qw\"er", ""])
|
||||
|
@ -186,12 +187,12 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testUTF16WithBigEndianBOM() {
|
||||
let csvString = "abab,,cdcd,efef\r\n😆zxcv,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF16BigEndianStringEncoding
|
||||
var mutableData = NSMutableData()
|
||||
mutableData.appendBytes(utf16BigEndianBOM, length: utf16BigEndianBOM.count)
|
||||
mutableData.appendData(csvString.dataUsingEncoding(encoding)!)
|
||||
let stream = NSInputStream(data: mutableData)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .Big)
|
||||
let encoding = String.Encoding.utf16BigEndian
|
||||
var mutableData = Data()
|
||||
mutableData.append(utf16BigEndianBOM, count: utf16BigEndianBOM.count)
|
||||
mutableData.append(csvString.data(using: encoding)!)
|
||||
let stream = InputStream(data: mutableData as Data)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .big)
|
||||
let records = getRecords(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["😆zxcv", "asdf", "qw\"er", ""])
|
||||
|
@ -199,12 +200,12 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testUTF16WithLittleEndianBOM() {
|
||||
let csvString = "abab,,cdcd,efef\r\nzxcv😆,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF16LittleEndianStringEncoding
|
||||
var mutableData = NSMutableData()
|
||||
mutableData.appendBytes(utf16LittleEndianBOM, length: utf16LittleEndianBOM.count)
|
||||
mutableData.appendData(csvString.dataUsingEncoding(encoding)!)
|
||||
let stream = NSInputStream(data: mutableData)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .Little)
|
||||
let encoding = String.Encoding.utf16LittleEndian
|
||||
var mutableData = Data()
|
||||
mutableData.append(utf16LittleEndianBOM, count: utf16LittleEndianBOM.count)
|
||||
mutableData.append(csvString.data(using: encoding)!)
|
||||
let stream = InputStream(data: mutableData as Data)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF16.self, endian: .little)
|
||||
let records = getRecords(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv😆", "asdf", "qw\"er", ""])
|
||||
|
@ -212,11 +213,11 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testUTF32WithNativeEndianBOM() {
|
||||
let csvString = "😆abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF32StringEncoding
|
||||
var mutableData = NSMutableData()
|
||||
mutableData.appendData(csvString.dataUsingEncoding(encoding)!)
|
||||
let stream = NSInputStream(data: mutableData)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .Unknown)
|
||||
let encoding = String.Encoding.utf32
|
||||
var mutableData = Data()
|
||||
mutableData.append(csvString.data(using: encoding)!)
|
||||
let stream = InputStream(data: mutableData as Data)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .unknown)
|
||||
let records = getRecords(csv: csv)
|
||||
XCTAssertEqual(records[0], ["😆abab", "", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
|
@ -224,12 +225,12 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testUTF32WithBigEndianBOM() {
|
||||
let csvString = "abab,,cd😆cd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF32BigEndianStringEncoding
|
||||
var mutableData = NSMutableData()
|
||||
mutableData.appendBytes(utf32BigEndianBOM, length: utf32BigEndianBOM.count)
|
||||
mutableData.appendData(csvString.dataUsingEncoding(encoding)!)
|
||||
let stream = NSInputStream(data: mutableData)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .Big)
|
||||
let encoding = String.Encoding.utf32BigEndian
|
||||
var mutableData = Data()
|
||||
mutableData.append(utf32BigEndianBOM, count: utf32BigEndianBOM.count)
|
||||
mutableData.append(csvString.data(using: encoding)!)
|
||||
let stream = InputStream(data: mutableData as Data)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .big)
|
||||
let records = getRecords(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cd😆cd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
|
@ -237,12 +238,12 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testUTF32WithLittleEndianBOM() {
|
||||
let csvString = "abab,,cdcd,ef😆ef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF32LittleEndianStringEncoding
|
||||
var mutableData = NSMutableData()
|
||||
mutableData.appendBytes(utf32LittleEndianBOM, length: utf32LittleEndianBOM.count)
|
||||
mutableData.appendData(csvString.dataUsingEncoding(encoding)!)
|
||||
let stream = NSInputStream(data: mutableData)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .Little)
|
||||
let encoding = String.Encoding.utf32LittleEndian
|
||||
var mutableData = Data()
|
||||
mutableData.append(utf32LittleEndianBOM, count: utf32LittleEndianBOM.count)
|
||||
mutableData.append(csvString.data(using: encoding)!)
|
||||
let stream = InputStream(data: mutableData as Data)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF32.self, endian: .little)
|
||||
let records = getRecords(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "ef😆ef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
|
@ -262,7 +263,7 @@ class CSVReaderTests: XCTestCase {
|
|||
// ]
|
||||
// }
|
||||
|
||||
func parse(csv csv: String) -> [[String]] {
|
||||
func parse(csv: String) -> [[String]] {
|
||||
let reader = try! CSV(string: csv)
|
||||
var records = [[String]]()
|
||||
for row in reader {
|
||||
|
@ -271,7 +272,7 @@ class CSVReaderTests: XCTestCase {
|
|||
return records
|
||||
}
|
||||
|
||||
func getRecords(csv csv: CSV) -> [[String]] {
|
||||
func getRecords(csv: CSV) -> [[String]] {
|
||||
var records = [[String]]()
|
||||
for row in csv {
|
||||
records.append(row)
|
||||
|
|
|
@ -162,7 +162,7 @@ class CSVTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testCSVState1() {
|
||||
let it = "あ,い1,\"う\",えお\n,,x,".unicodeScalars.generate()
|
||||
let it = "あ,い1,\"う\",えお\n,,x,".unicodeScalars.makeIterator()
|
||||
var csv = try! CSV(iterator: it, hasHeaderRow: defaultHasHeaderRow, delimiter: defaultDelimiter)
|
||||
|
||||
var rows = [[String]]()
|
||||
|
|
Loading…
Reference in New Issue