Merge pull request #4 from yaslab/swift-2.2
This commit is contained in:
commit
7cd1d968dc
|
@ -7,26 +7,30 @@
|
|||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0E0F16091D197D6000C92580 /* AnyIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F16081D197D6000C92580 /* AnyIterator.swift */; };
|
||||
0E0F160A1D197D6000C92580 /* AnyIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F16081D197D6000C92580 /* AnyIterator.swift */; };
|
||||
0E0F160B1D197D6000C92580 /* AnyIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F16081D197D6000C92580 /* AnyIterator.swift */; };
|
||||
0E0F160C1D197D6000C92580 /* AnyIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F16081D197D6000C92580 /* AnyIterator.swift */; };
|
||||
0E0F160E1D197DB800C92580 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F160D1D197DB800C92580 /* Endian.swift */; };
|
||||
0E0F160F1D197DB800C92580 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F160D1D197DB800C92580 /* Endian.swift */; };
|
||||
0E0F16101D197DB800C92580 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F160D1D197DB800C92580 /* Endian.swift */; };
|
||||
0E0F16111D197DB800C92580 /* Endian.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E0F160D1D197DB800C92580 /* Endian.swift */; };
|
||||
0E7E8C8C1D0BC7BB0057A1C1 /* CSV.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E7E8C811D0BC7BB0057A1C1 /* CSV.framework */; };
|
||||
0E7E8CA01D0BC7F10057A1C1 /* ByteOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9C1D0BC7F10057A1C1 /* ByteOrder.swift */; };
|
||||
0E7E8CA11D0BC7F10057A1C1 /* CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */; };
|
||||
0E7E8CA21D0BC7F10057A1C1 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */; };
|
||||
0E7E8CA31D0BC7F10057A1C1 /* CSVVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0E7E8CA91D0BC8050057A1C1 /* CSVReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8CA61D0BC8050057A1C1 /* CSVReaderTests.swift */; };
|
||||
0E7E8CAA1D0BC8050057A1C1 /* CSVTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8CA71D0BC8050057A1C1 /* CSVTests.swift */; };
|
||||
0E7E8CBD1D0BC9D70057A1C1 /* ByteOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9C1D0BC7F10057A1C1 /* ByteOrder.swift */; };
|
||||
0E7E8CBE1D0BC9D70057A1C1 /* CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */; };
|
||||
0E7E8CBF1D0BC9D70057A1C1 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */; };
|
||||
0E7E8CC01D0BC9D70057A1C1 /* CSVVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0E7E8CD01D0BCA2A0057A1C1 /* CSV.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E7E8CC61D0BCA2A0057A1C1 /* CSV.framework */; };
|
||||
0E7E8CDD1D0BCA840057A1C1 /* CSVReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8CA61D0BC8050057A1C1 /* CSVReaderTests.swift */; };
|
||||
0E7E8CDE1D0BCA840057A1C1 /* CSVTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8CA71D0BC8050057A1C1 /* CSVTests.swift */; };
|
||||
0E7E8CDF1D0BCA8E0057A1C1 /* ByteOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9C1D0BC7F10057A1C1 /* ByteOrder.swift */; };
|
||||
0E7E8CE01D0BCA8E0057A1C1 /* CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */; };
|
||||
0E7E8CE11D0BCA8E0057A1C1 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */; };
|
||||
0E7E8CE21D0BCA8E0057A1C1 /* CSVVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0E7E8CF21D0BCD0B0057A1C1 /* CSV.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E7E8CE81D0BCD0B0057A1C1 /* CSV.framework */; };
|
||||
0E7E8CFF1D0BCDCF0057A1C1 /* ByteOrder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9C1D0BC7F10057A1C1 /* ByteOrder.swift */; };
|
||||
0E7E8D001D0BCDCF0057A1C1 /* CSV.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */; };
|
||||
0E7E8D011D0BCDCF0057A1C1 /* CSVError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */; };
|
||||
0E7E8D021D0BCDCF0057A1C1 /* CSVVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
|
@ -43,6 +47,14 @@
|
|||
0E9317DE1D0DBCC500AC20A0 /* ReadmeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317DD1D0DBCC500AC20A0 /* ReadmeTests.swift */; };
|
||||
0E9317DF1D0DBCC500AC20A0 /* ReadmeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317DD1D0DBCC500AC20A0 /* ReadmeTests.swift */; };
|
||||
0E9317E01D0DBCC500AC20A0 /* ReadmeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9317DD1D0DBCC500AC20A0 /* ReadmeTests.swift */; };
|
||||
0EA2AB7C1D183B45003EC967 /* BinaryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB7B1D183B45003EC967 /* BinaryReader.swift */; };
|
||||
0EA2AB7D1D183B45003EC967 /* BinaryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB7B1D183B45003EC967 /* BinaryReader.swift */; };
|
||||
0EA2AB7E1D183B45003EC967 /* BinaryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB7B1D183B45003EC967 /* BinaryReader.swift */; };
|
||||
0EA2AB7F1D183B45003EC967 /* BinaryReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB7B1D183B45003EC967 /* BinaryReader.swift */; };
|
||||
0EA2AB811D183BA9003EC967 /* UnicodeIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */; };
|
||||
0EA2AB821D183BA9003EC967 /* UnicodeIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */; };
|
||||
0EA2AB831D183BA9003EC967 /* UnicodeIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */; };
|
||||
0EA2AB841D183BA9003EC967 /* UnicodeIterator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
|
@ -70,9 +82,10 @@
|
|||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0E0F16081D197D6000C92580 /* AnyIterator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyIterator.swift; sourceTree = "<group>"; };
|
||||
0E0F160D1D197DB800C92580 /* Endian.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Endian.swift; sourceTree = "<group>"; };
|
||||
0E7E8C811D0BC7BB0057A1C1 /* CSV.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CSV.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0E7E8C8B1D0BC7BB0057A1C1 /* CSVTests-iOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "CSVTests-iOS.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
0E7E8C9C1D0BC7F10057A1C1 /* ByteOrder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ByteOrder.swift; sourceTree = "<group>"; };
|
||||
0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSV.swift; sourceTree = "<group>"; };
|
||||
0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSVError.swift; sourceTree = "<group>"; };
|
||||
0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSVVersion.h; sourceTree = "<group>"; };
|
||||
|
@ -88,6 +101,8 @@
|
|||
0E9317D31D0DB2F200AC20A0 /* CSV+init.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CSV+init.swift"; sourceTree = "<group>"; };
|
||||
0E9317D81D0DB30800AC20A0 /* CSV+subscript.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CSV+subscript.swift"; sourceTree = "<group>"; };
|
||||
0E9317DD1D0DBCC500AC20A0 /* ReadmeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadmeTests.swift; sourceTree = "<group>"; };
|
||||
0EA2AB7B1D183B45003EC967 /* BinaryReader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinaryReader.swift; sourceTree = "<group>"; };
|
||||
0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnicodeIterator.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -172,13 +187,16 @@
|
|||
0E7E8C9B1D0BC7F10057A1C1 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0E7E8C9C1D0BC7F10057A1C1 /* ByteOrder.swift */,
|
||||
0E0F16081D197D6000C92580 /* AnyIterator.swift */,
|
||||
0EA2AB7B1D183B45003EC967 /* BinaryReader.swift */,
|
||||
0E7E8C9D1D0BC7F10057A1C1 /* CSV.swift */,
|
||||
0E9317D31D0DB2F200AC20A0 /* CSV+init.swift */,
|
||||
0E9317D81D0DB30800AC20A0 /* CSV+subscript.swift */,
|
||||
0E7E8C9E1D0BC7F10057A1C1 /* CSVError.swift */,
|
||||
0E7E8C9F1D0BC7F10057A1C1 /* CSVVersion.h */,
|
||||
0E0F160D1D197DB800C92580 /* Endian.swift */,
|
||||
0E7E8CAC1D0BC8610057A1C1 /* Info.plist */,
|
||||
0EA2AB801D183BA9003EC967 /* UnicodeIterator.swift */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
|
@ -373,7 +391,7 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastSwiftUpdateCheck = 0730;
|
||||
LastUpgradeCheck = 0730;
|
||||
LastUpgradeCheck = 0800;
|
||||
ORGANIZATIONNAME = yaslab;
|
||||
TargetAttributes = {
|
||||
0E7E8C801D0BC7BB0057A1C1 = {
|
||||
|
@ -387,9 +405,11 @@
|
|||
};
|
||||
0E7E8CC51D0BCA2A0057A1C1 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
0E7E8CCE1D0BCA2A0057A1C1 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 0800;
|
||||
};
|
||||
0E7E8CE71D0BCD0B0057A1C1 = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
|
@ -480,10 +500,13 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0E9317D51D0DB2F200AC20A0 /* CSV+init.swift in Sources */,
|
||||
0E0F160A1D197D6000C92580 /* AnyIterator.swift in Sources */,
|
||||
0EA2AB821D183BA9003EC967 /* UnicodeIterator.swift in Sources */,
|
||||
0E9317DA1D0DB30800AC20A0 /* CSV+subscript.swift in Sources */,
|
||||
0E7E8CA11D0BC7F10057A1C1 /* CSV.swift in Sources */,
|
||||
0E0F160F1D197DB800C92580 /* Endian.swift in Sources */,
|
||||
0E7E8CA21D0BC7F10057A1C1 /* CSVError.swift in Sources */,
|
||||
0E7E8CA01D0BC7F10057A1C1 /* ByteOrder.swift in Sources */,
|
||||
0EA2AB7D1D183B45003EC967 /* BinaryReader.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -502,10 +525,13 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0E9317D71D0DB2F200AC20A0 /* CSV+init.swift in Sources */,
|
||||
0E0F160C1D197D6000C92580 /* AnyIterator.swift in Sources */,
|
||||
0EA2AB841D183BA9003EC967 /* UnicodeIterator.swift in Sources */,
|
||||
0E9317DC1D0DB30800AC20A0 /* CSV+subscript.swift in Sources */,
|
||||
0E7E8CBE1D0BC9D70057A1C1 /* CSV.swift in Sources */,
|
||||
0E0F16111D197DB800C92580 /* Endian.swift in Sources */,
|
||||
0E7E8CBF1D0BC9D70057A1C1 /* CSVError.swift in Sources */,
|
||||
0E7E8CBD1D0BC9D70057A1C1 /* ByteOrder.swift in Sources */,
|
||||
0EA2AB7F1D183B45003EC967 /* BinaryReader.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -514,10 +540,13 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0E9317D41D0DB2F200AC20A0 /* CSV+init.swift in Sources */,
|
||||
0E0F16091D197D6000C92580 /* AnyIterator.swift in Sources */,
|
||||
0EA2AB811D183BA9003EC967 /* UnicodeIterator.swift in Sources */,
|
||||
0E9317D91D0DB30800AC20A0 /* CSV+subscript.swift in Sources */,
|
||||
0E7E8CE01D0BCA8E0057A1C1 /* CSV.swift in Sources */,
|
||||
0E0F160E1D197DB800C92580 /* Endian.swift in Sources */,
|
||||
0E7E8CE11D0BCA8E0057A1C1 /* CSVError.swift in Sources */,
|
||||
0E7E8CDF1D0BCA8E0057A1C1 /* ByteOrder.swift in Sources */,
|
||||
0EA2AB7C1D183B45003EC967 /* BinaryReader.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -536,10 +565,13 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0E9317D61D0DB2F200AC20A0 /* CSV+init.swift in Sources */,
|
||||
0E0F160B1D197D6000C92580 /* AnyIterator.swift in Sources */,
|
||||
0EA2AB831D183BA9003EC967 /* UnicodeIterator.swift in Sources */,
|
||||
0E9317DB1D0DB30800AC20A0 /* CSV+subscript.swift in Sources */,
|
||||
0E7E8D001D0BCDCF0057A1C1 /* CSV.swift in Sources */,
|
||||
0E0F16101D197DB800C92580 /* Endian.swift in Sources */,
|
||||
0E7E8D011D0BCDCF0057A1C1 /* CSVError.swift in Sources */,
|
||||
0E7E8CFF1D0BCDCF0057A1C1 /* ByteOrder.swift in Sources */,
|
||||
0EA2AB7E1D183B45003EC967 /* BinaryReader.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -696,6 +728,7 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = net.yaslab.CSV;
|
||||
PRODUCT_NAME = CSV;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -716,6 +749,7 @@
|
|||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-iOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -754,6 +788,7 @@
|
|||
PRODUCT_NAME = CSV;
|
||||
SDKROOT = watchos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
TARGETED_DEVICE_FAMILY = 4;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
};
|
||||
|
@ -777,6 +812,7 @@
|
|||
PRODUCT_NAME = CSV;
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -798,6 +834,8 @@
|
|||
PRODUCT_NAME = CSV;
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -812,6 +850,7 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-OSX";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
|
@ -826,6 +865,8 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-OSX";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 3.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -862,6 +903,7 @@
|
|||
PRODUCT_NAME = CSV;
|
||||
SDKROOT = appletvos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
TARGETED_DEVICE_FAMILY = 3;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
};
|
||||
|
@ -887,6 +929,7 @@
|
|||
PRODUCT_BUNDLE_IDENTIFIER = "net.yaslab.CSVTests-tvOS";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = appletvos;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
TVOS_DEPLOYMENT_TARGET = 9.2;
|
||||
};
|
||||
name = Release;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0730"
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
14
README.md
14
README.md
|
@ -23,7 +23,8 @@ for row in try! CSV(string: "1,foo\n2,bar") {
|
|||
```swift
|
||||
import CSV
|
||||
|
||||
for row in try! CSV(path: "/path/to/file.csv") {
|
||||
let stream = NSInputStream(fileAtPath: "/path/to/file.csv")!
|
||||
for row in try! CSV(stream: stream) {
|
||||
print("\(row)")
|
||||
}
|
||||
```
|
||||
|
@ -64,8 +65,9 @@ If you use a file path, you can provide the character encoding to initializer.
|
|||
|
||||
```swift
|
||||
let csv = try! CSV(
|
||||
path: "/path/to/file.csv",
|
||||
encoding: NSUTF8StringEncoding)
|
||||
stream: NSInputStream(fileAtPath: "/path/to/file.csv")!,
|
||||
codecType: UTF16.self,
|
||||
endian: .Big)
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
@ -73,13 +75,13 @@ let csv = try! CSV(
|
|||
### CocoaPods
|
||||
|
||||
```ruby
|
||||
pod 'CSV.swift', '~> 0.2'
|
||||
pod 'CSV.swift', '~> 0.3'
|
||||
```
|
||||
|
||||
### Carthage
|
||||
|
||||
```
|
||||
github "yaslab/CSV.swift" ~> 0.2
|
||||
github "yaslab/CSV.swift" ~> 0.3
|
||||
```
|
||||
|
||||
### Swift Package Manager
|
||||
|
@ -90,7 +92,7 @@ import PackageDescription
|
|||
let package = Package(
|
||||
name: "PackageName",
|
||||
dependencies: [
|
||||
.Package(url: "https://github.com/yaslab/CSV.swift", majorVersion: 0, minor: 2)
|
||||
.Package(url: "https://github.com/yaslab/CSV.swift", majorVersion: 0, minor: 3)
|
||||
]
|
||||
)
|
||||
```
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
//
|
||||
// AnyIterator.swift
|
||||
// CSV
|
||||
//
|
||||
// Created by Yasuhiro Hatta on 2016/06/21.
|
||||
// Copyright © 2016 yaslab. All rights reserved.
|
||||
//
|
||||
|
||||
internal struct AnyIterator<T>: GeneratorType {
|
||||
|
||||
private var _base_next: (() -> T?)
|
||||
|
||||
internal init<U: GeneratorType where U.Element == T>(base: U) {
|
||||
var base = base
|
||||
_base_next = { base.next() }
|
||||
}
|
||||
|
||||
internal mutating func next() -> T? {
|
||||
return _base_next()
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
//
|
||||
// BinaryReader.swift
|
||||
// CSV
|
||||
//
|
||||
// Created by Yasuhiro Hatta on 2016/06/20.
|
||||
// Copyright © 2016 yaslab. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
internal let utf8BOM: [UInt8] = [0xef, 0xbb, 0xbf]
|
||||
internal let utf16BigEndianBOM: [UInt8] = [0xfe, 0xff]
|
||||
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)? {
|
||||
if length >= 4 {
|
||||
if memcmp(buffer, utf32BigEndianBOM, 4) == 0 {
|
||||
return (.Big, 4)
|
||||
}
|
||||
if memcmp(buffer, utf32LittleEndianBOM, 4) == 0 {
|
||||
return (.Little, 4)
|
||||
}
|
||||
}
|
||||
if length >= 3 {
|
||||
if memcmp(buffer, utf8BOM, 3) == 0 {
|
||||
return (.Unknown, 3)
|
||||
}
|
||||
}
|
||||
if length >= 2 {
|
||||
if memcmp(buffer, utf16BigEndianBOM, 2) == 0 {
|
||||
return (.Big, 2)
|
||||
}
|
||||
if memcmp(buffer, utf16LittleEndianBOM, 2) == 0 {
|
||||
return (.Little, 2)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
internal class BinaryReader {
|
||||
|
||||
private let stream: NSInputStream
|
||||
private let endian: Endian
|
||||
private let closeOnDeinit: Bool
|
||||
|
||||
private var buffer = [UInt8](count: 4, repeatedValue: 0)
|
||||
|
||||
private var tempBuffer = [UInt8](count: 4, repeatedValue: 0)
|
||||
private let tempBufferSize = 4
|
||||
private var tempBufferOffset = 0
|
||||
|
||||
internal init(stream: NSInputStream, endian: Endian = .Unknown, closeOnDeinit: Bool = true) throws {
|
||||
var endian = endian
|
||||
|
||||
if stream.streamStatus == .NotOpen {
|
||||
stream.open()
|
||||
}
|
||||
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
|
||||
}
|
||||
endian = e
|
||||
tempBufferOffset = l
|
||||
}
|
||||
|
||||
self.stream = stream
|
||||
self.endian = endian
|
||||
self.closeOnDeinit = closeOnDeinit
|
||||
}
|
||||
|
||||
deinit {
|
||||
if closeOnDeinit && stream.streamStatus != .Closed {
|
||||
stream.close()
|
||||
}
|
||||
}
|
||||
|
||||
internal var hasBytesAvailable: Bool {
|
||||
return stream.hasBytesAvailable
|
||||
}
|
||||
|
||||
private func readStream(_ buffer: UnsafeMutablePointer<UInt8>, maxLength: Int) throws -> Int {
|
||||
if stream.streamStatus != .Open {
|
||||
throw CSVError.CannotReadFile
|
||||
}
|
||||
|
||||
var i = 0
|
||||
while tempBufferOffset < tempBufferSize {
|
||||
buffer[i] = tempBuffer[tempBufferOffset]
|
||||
i += 1
|
||||
tempBufferOffset += 1
|
||||
if i >= maxLength {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return stream.read(buffer + i, maxLength: maxLength - i)
|
||||
}
|
||||
|
||||
internal func readUInt8() throws -> UInt8 {
|
||||
let bufferSize = 1
|
||||
let length = try readStream(&buffer, maxLength: bufferSize)
|
||||
if length < 0 {
|
||||
throw CSVError.StreamErrorHasOccurred(error: stream.streamError!)
|
||||
}
|
||||
if length != bufferSize {
|
||||
throw CSVError.CannotReadFile
|
||||
}
|
||||
return buffer[0]
|
||||
}
|
||||
|
||||
internal func readUInt16() throws -> UInt16 {
|
||||
let bufferSize = 2
|
||||
let length = try readStream(&buffer, maxLength: bufferSize)
|
||||
if length < 0 {
|
||||
throw CSVError.StreamErrorHasOccurred(error: stream.streamError!)
|
||||
}
|
||||
if length != bufferSize {
|
||||
throw CSVError.StringEncodingMismatch
|
||||
}
|
||||
let tmp = UnsafeMutablePointer<UInt16>(buffer)
|
||||
switch endian {
|
||||
case .Big:
|
||||
return CFSwapInt16BigToHost(tmp[0])
|
||||
case .Little:
|
||||
return CFSwapInt16LittleToHost(tmp[0])
|
||||
default:
|
||||
throw CSVError.StringEndianMismatch
|
||||
}
|
||||
}
|
||||
|
||||
internal func readUInt32() throws -> UInt32 {
|
||||
let bufferSize = 4
|
||||
let length = try readStream(&buffer, maxLength: bufferSize)
|
||||
if length < 0 {
|
||||
throw CSVError.StreamErrorHasOccurred(error: stream.streamError!)
|
||||
}
|
||||
if length != 4 {
|
||||
throw CSVError.StringEncodingMismatch
|
||||
}
|
||||
let tmp = UnsafeMutablePointer<UInt32>(buffer)
|
||||
switch endian {
|
||||
case .Big:
|
||||
return CFSwapInt32BigToHost(tmp[0])
|
||||
case .Little:
|
||||
return CFSwapInt32LittleToHost(tmp[0])
|
||||
default:
|
||||
throw CSVError.StringEndianMismatch
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension BinaryReader {
|
||||
|
||||
internal struct UInt8Iterator: SequenceType, GeneratorType {
|
||||
|
||||
private let reader: BinaryReader
|
||||
|
||||
private init(reader: BinaryReader) {
|
||||
self.reader = reader
|
||||
}
|
||||
|
||||
internal mutating func next() -> UInt8? {
|
||||
if !reader.hasBytesAvailable {
|
||||
return nil
|
||||
}
|
||||
do {
|
||||
return try reader.readUInt8()
|
||||
}
|
||||
catch /*let error*/ {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal func makeUInt8Iterator() -> UInt8Iterator {
|
||||
return UInt8Iterator(reader: self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension BinaryReader {
|
||||
|
||||
internal struct UInt16Iterator: SequenceType, GeneratorType {
|
||||
|
||||
private let reader: BinaryReader
|
||||
|
||||
private init(reader: BinaryReader) {
|
||||
self.reader = reader
|
||||
}
|
||||
|
||||
internal mutating func next() -> UInt16? {
|
||||
if !reader.hasBytesAvailable {
|
||||
return nil
|
||||
}
|
||||
do {
|
||||
return try reader.readUInt16()
|
||||
}
|
||||
catch /*let error*/ {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal func makeUInt16Iterator() -> UInt16Iterator {
|
||||
return UInt16Iterator(reader: self)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension BinaryReader {
|
||||
|
||||
internal struct UInt32Iterator: SequenceType, GeneratorType {
|
||||
|
||||
private let reader: BinaryReader
|
||||
|
||||
private init(reader: BinaryReader) {
|
||||
self.reader = reader
|
||||
}
|
||||
|
||||
internal mutating func next() -> UInt32? {
|
||||
if !reader.hasBytesAvailable {
|
||||
return nil
|
||||
}
|
||||
do {
|
||||
return try reader.readUInt32()
|
||||
}
|
||||
catch /*let error*/ {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal func makeUInt32Iterator() -> UInt32Iterator {
|
||||
return UInt32Iterator(reader: self)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
//
|
||||
// ByteOrder.swift
|
||||
// CSV
|
||||
//
|
||||
// Created by Yasuhiro Hatta on 2016/06/11.
|
||||
//
|
||||
//
|
||||
|
||||
import CoreFoundation
|
||||
|
||||
internal func ReadBigInt16(base: UnsafePointer<Void>, byteOffset: Int) -> UInt16 {
|
||||
let bytes = UnsafePointer<UInt8>(base).advancedBy(byteOffset)
|
||||
let int16Array = UnsafePointer<UInt16>(bytes)
|
||||
return CFSwapInt16BigToHost(int16Array[0])
|
||||
}
|
||||
|
||||
internal func ReadBigInt32(base: UnsafePointer<Void>, byteOffset: Int) -> UInt32 {
|
||||
let bytes = UnsafePointer<UInt8>(base).advancedBy(byteOffset)
|
||||
let int32Array = UnsafePointer<UInt32>(bytes)
|
||||
return CFSwapInt32BigToHost(int32Array[0])
|
||||
}
|
||||
|
||||
internal func ReadLittleInt16(base: UnsafePointer<Void>, byteOffset: Int) -> UInt16 {
|
||||
let bytes = UnsafePointer<UInt8>(base).advancedBy(byteOffset)
|
||||
let int16Array = UnsafePointer<UInt16>(bytes)
|
||||
return CFSwapInt16LittleToHost(int16Array[0])
|
||||
}
|
||||
|
||||
internal func ReadLittleInt32(base: UnsafePointer<Void>, byteOffset: Int) -> UInt32 {
|
||||
let bytes = UnsafePointer<UInt8>(base).advancedBy(byteOffset)
|
||||
let int32Array = UnsafePointer<UInt32>(bytes)
|
||||
return CFSwapInt32LittleToHost(int32Array[0])
|
||||
}
|
||||
|
||||
internal func IsBigEndian() -> Bool {
|
||||
return CFByteOrderGetCurrent() == CFByteOrder(CFByteOrderBigEndian.rawValue)
|
||||
}
|
|
@ -10,61 +10,27 @@ import Foundation
|
|||
|
||||
extension CSV {
|
||||
|
||||
public convenience init(
|
||||
path: String,
|
||||
public init(
|
||||
stream: NSInputStream,
|
||||
hasHeaderRow: Bool = defaultHasHeaderRow,
|
||||
encoding: NSStringEncoding = defaultEncoding,
|
||||
delimiter: CChar = defaultDelimiter,
|
||||
bufferSize: Int = defaultBufferSize)
|
||||
delimiter: UnicodeScalar = defaultDelimiter)
|
||||
throws
|
||||
{
|
||||
guard let stream = NSInputStream(fileAtPath: path) else {
|
||||
throw CSVError.StreamError
|
||||
}
|
||||
try self.init(
|
||||
stream: stream,
|
||||
hasHeaderRow: hasHeaderRow,
|
||||
encoding: encoding,
|
||||
delimiter: delimiter,
|
||||
bufferSize: bufferSize)
|
||||
try self.init(stream: stream, codecType: UTF8.self, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
|
||||
}
|
||||
|
||||
public convenience init(
|
||||
url: NSURL,
|
||||
hasHeaderRow: Bool = defaultHasHeaderRow,
|
||||
encoding: NSStringEncoding = defaultEncoding,
|
||||
delimiter: CChar = defaultDelimiter,
|
||||
bufferSize: Int = defaultBufferSize)
|
||||
throws
|
||||
{
|
||||
guard let stream = NSInputStream(URL: url) else {
|
||||
throw CSVError.StreamError
|
||||
}
|
||||
try self.init(
|
||||
stream: stream,
|
||||
hasHeaderRow: hasHeaderRow,
|
||||
encoding: encoding,
|
||||
delimiter: delimiter,
|
||||
bufferSize: bufferSize)
|
||||
}
|
||||
|
||||
public convenience init(
|
||||
extension CSV {
|
||||
|
||||
public init(
|
||||
string: String,
|
||||
hasHeaderRow: Bool = defaultHasHeaderRow,
|
||||
delimiter: CChar = defaultDelimiter,
|
||||
bufferSize: Int = defaultBufferSize)
|
||||
delimiter: UnicodeScalar = defaultDelimiter)
|
||||
throws
|
||||
{
|
||||
let encoding = defaultEncoding
|
||||
guard let data = string.dataUsingEncoding(encoding) else {
|
||||
throw CSVError.StringEncodingMismatch
|
||||
}
|
||||
try self.init(
|
||||
stream: NSInputStream(data: data),
|
||||
hasHeaderRow: hasHeaderRow,
|
||||
encoding: encoding,
|
||||
delimiter: delimiter,
|
||||
bufferSize: bufferSize)
|
||||
let iterator = string.unicodeScalars.generate()
|
||||
try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,21 +6,16 @@
|
|||
// Copyright © 2016 yaslab. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension CSV {
|
||||
|
||||
public subscript(key: String) -> String? {
|
||||
get {
|
||||
guard let headerRow = headerRow else {
|
||||
guard let headerRow = headerRow, let currentRow = currentRow else {
|
||||
return nil
|
||||
}
|
||||
guard let index = headerRow.indexOf(key) else {
|
||||
return nil
|
||||
}
|
||||
guard let currentRow = currentRow else {
|
||||
return nil
|
||||
}
|
||||
if index >= currentRow.count {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,358 +3,240 @@
|
|||
// CSV
|
||||
//
|
||||
// Created by Yasuhiro Hatta on 2016/06/11.
|
||||
//
|
||||
// Copyright © 2016 yaslab. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
private let LF: UInt32 = 0x0a //'\n'
|
||||
private let CR: UInt32 = 0x0d //'\r'
|
||||
private let DQUOTE: UInt32 = 0x22 //'"'
|
||||
private let LF = "\n".unicodeScalars.first!
|
||||
private let CR = "\r".unicodeScalars.first!
|
||||
private let DQUOTE = "\"".unicodeScalars.first!
|
||||
|
||||
internal let defaultHasHeaderRow = false
|
||||
internal let defaultEncoding = NSUTF8StringEncoding
|
||||
internal let defaultDelimiter: CChar = 0x2c //','
|
||||
internal let defaultBufferSize = 8192
|
||||
internal let defaultDelimiter = ",".unicodeScalars.first!
|
||||
|
||||
internal let utf8BOM: [UInt8] = [0xef, 0xbb, 0xbf]
|
||||
internal let utf16BigEndianBOM: [UInt8] = [0xfe, 0xff]
|
||||
internal let utf16LittleEndianBOM: [UInt8] = [0xff, 0xfe]
|
||||
internal let utf32BigEndianBOM: [UInt8] = [0x00, 0x00, 0xfe, 0xff]
|
||||
internal let utf32LittleEndianBOM: [UInt8] = [0xff, 0xfe, 0x00, 0x00]
|
||||
public struct CSV: GeneratorType, SequenceType {
|
||||
|
||||
public class CSV: SequenceType, GeneratorType {
|
||||
private var iterator: AnyIterator<UnicodeScalar>
|
||||
private let delimiter: UnicodeScalar
|
||||
|
||||
internal let stream: NSInputStream
|
||||
internal let encoding: NSStringEncoding
|
||||
internal let delimiter: UInt32
|
||||
internal let bufferSize: Int
|
||||
|
||||
internal var buffer: UnsafeMutablePointer<UInt8>!
|
||||
internal var bufferOffset: Int
|
||||
internal var lastReadCount: Int
|
||||
|
||||
internal let charWidth: Int
|
||||
|
||||
internal let fieldBuffer: NSMutableData
|
||||
|
||||
internal var closed: Bool = false
|
||||
private var back: UnicodeScalar? = nil
|
||||
|
||||
internal var currentRow: [String]? = nil
|
||||
|
||||
/**
|
||||
CSV header row. To set a value for this property, you set `true` to `hasHeaerRow` in initializer.
|
||||
*/
|
||||
/// CSV header row. To set a value for this property, you set `true` to `hasHeaerRow` in initializer.
|
||||
public var headerRow: [String]? { return _headerRow }
|
||||
private var _headerRow: [String]? = nil
|
||||
|
||||
/**
|
||||
The value is set when an error occurs.
|
||||
*/
|
||||
public private(set) var lastError: CSVError? = nil
|
||||
|
||||
/**
|
||||
Create CSV instance with `NSInputStream`.
|
||||
|
||||
- parameter stream: An `NSInputStream` object. If the stream is not open, initializer opens automatically.
|
||||
- parameter hasHeaderRow: `true` if the CSV has a header row, otherwise `false`. Default: `false`.
|
||||
- parameter encoding: The character encoding for `stream`. Default: `NSUTF8StringEncoding`.
|
||||
- parameter delimiter: Default: `","`.
|
||||
- parameter bufferSize: Size in bytes to be read at a time from the stream. Default: `8192`.
|
||||
*/
|
||||
public init(
|
||||
stream: NSInputStream,
|
||||
hasHeaderRow: Bool = defaultHasHeaderRow,
|
||||
encoding: NSStringEncoding = defaultEncoding,
|
||||
delimiter: CChar = defaultDelimiter,
|
||||
bufferSize: Int = defaultBufferSize)
|
||||
internal init<T: GeneratorType where T.Element == UnicodeScalar>(
|
||||
iterator: T,
|
||||
hasHeaderRow: Bool,
|
||||
delimiter: UnicodeScalar)
|
||||
throws
|
||||
{
|
||||
self.stream = stream
|
||||
|
||||
var bs = bufferSize
|
||||
if bs < 0 {
|
||||
throw CSVError.ParameterError
|
||||
}
|
||||
if bs < 8 {
|
||||
bs = 8
|
||||
}
|
||||
let mod = bs % 4
|
||||
if mod != 0 {
|
||||
bs += 4 - mod
|
||||
}
|
||||
self.bufferSize = bs
|
||||
|
||||
self.delimiter = UInt32(delimiter)
|
||||
|
||||
let b = malloc(bufferSize)
|
||||
if b == nil {
|
||||
throw CSVError.MemoryAllocationFailed
|
||||
}
|
||||
self.buffer = UnsafeMutablePointer<UInt8>(b)
|
||||
self.bufferOffset = 0
|
||||
|
||||
self.fieldBuffer = NSMutableData()
|
||||
|
||||
if stream.streamStatus == .NotOpen {
|
||||
stream.open()
|
||||
}
|
||||
if stream.streamStatus != .Open {
|
||||
throw CSVError.StreamError
|
||||
}
|
||||
|
||||
self.lastReadCount = stream.read(self.buffer, maxLength: bufferSize)
|
||||
|
||||
var e = encoding
|
||||
|
||||
switch encoding {
|
||||
case NSUTF16StringEncoding,
|
||||
NSUTF16BigEndianStringEncoding,
|
||||
NSUTF16LittleEndianStringEncoding:
|
||||
|
||||
charWidth = 2
|
||||
if encoding == NSUTF16StringEncoding {
|
||||
let nativeEndian = IsBigEndian()
|
||||
? NSUTF16BigEndianStringEncoding
|
||||
: NSUTF16LittleEndianStringEncoding
|
||||
e = nativeEndian
|
||||
if lastReadCount >= charWidth {
|
||||
if memcmp(buffer, utf16BigEndianBOM, charWidth) == 0 {
|
||||
e = NSUTF16BigEndianStringEncoding
|
||||
self.bufferOffset += charWidth
|
||||
}
|
||||
else if memcmp(buffer, utf16LittleEndianBOM, charWidth) == 0 {
|
||||
e = NSUTF16LittleEndianStringEncoding
|
||||
self.bufferOffset += charWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case NSUTF32StringEncoding,
|
||||
NSUTF32BigEndianStringEncoding,
|
||||
NSUTF32LittleEndianStringEncoding:
|
||||
|
||||
charWidth = 4
|
||||
if encoding == NSUTF32StringEncoding {
|
||||
let nativeEndian = IsBigEndian()
|
||||
? NSUTF32BigEndianStringEncoding
|
||||
: NSUTF32LittleEndianStringEncoding
|
||||
e = nativeEndian
|
||||
if lastReadCount >= charWidth {
|
||||
if memcmp(buffer, utf32BigEndianBOM, charWidth) == 0 {
|
||||
e = NSUTF32BigEndianStringEncoding
|
||||
self.bufferOffset += charWidth
|
||||
}
|
||||
else if memcmp(buffer, utf32LittleEndianBOM, charWidth) == 0 {
|
||||
e = NSUTF32LittleEndianStringEncoding
|
||||
self.bufferOffset += charWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
charWidth = 1
|
||||
if encoding == NSUTF8StringEncoding {
|
||||
let bomSize = 3
|
||||
if lastReadCount >= bomSize {
|
||||
if memcmp(buffer, utf8BOM, charWidth) == 0 {
|
||||
self.bufferOffset += bomSize
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.encoding = e
|
||||
self.iterator = AnyIterator(base: iterator)
|
||||
self.delimiter = delimiter
|
||||
|
||||
if hasHeaderRow {
|
||||
guard let nextRow = next() else {
|
||||
throw CSVError.HeaderReadError
|
||||
guard let headerRow = next() else {
|
||||
throw CSVError.CannotReadHeaderRow
|
||||
}
|
||||
_headerRow = nextRow
|
||||
currentRow = nil
|
||||
_headerRow = headerRow
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
close()
|
||||
/// Create an instance with `InputStream`.
|
||||
///
|
||||
/// - parameter stream: An `InputStream` object. If the stream is not open, initializer opens automatically.
|
||||
/// - 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,
|
||||
codecType: T.Type,
|
||||
hasHeaderRow: Bool = defaultHasHeaderRow,
|
||||
delimiter: UnicodeScalar = defaultDelimiter)
|
||||
throws
|
||||
{
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
Close stream.
|
||||
*/
|
||||
public func close() {
|
||||
if !closed {
|
||||
stream.close()
|
||||
if buffer != nil {
|
||||
free(buffer)
|
||||
buffer = nil
|
||||
}
|
||||
closed = true
|
||||
}
|
||||
/// Create an instance with `InputStream`.
|
||||
///
|
||||
/// - parameter stream: An `InputStream` object. If the stream is not open, initializer opens automatically.
|
||||
/// - parameter codecType: A `UnicodeCodec` type for `stream`.
|
||||
/// - 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,
|
||||
codecType: T.Type,
|
||||
endian: Endian = .Big,
|
||||
hasHeaderRow: Bool = defaultHasHeaderRow,
|
||||
delimiter: UnicodeScalar = defaultDelimiter)
|
||||
throws
|
||||
{
|
||||
let reader = try BinaryReader(stream: stream, endian: endian, closeOnDeinit: true)
|
||||
let iterator = UnicodeIterator(input: reader.makeUInt16Iterator(), inputEncodingType: codecType)
|
||||
try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
|
||||
}
|
||||
|
||||
// MARK: GeneratorType
|
||||
/// Create an instance with `InputStream`.
|
||||
///
|
||||
/// - parameter stream: An `InputStream` object. If the stream is not open, initializer opens automatically.
|
||||
/// - parameter codecType: A `UnicodeCodec` type for `stream`.
|
||||
/// - 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,
|
||||
codecType: T.Type,
|
||||
endian: Endian = .Big,
|
||||
hasHeaderRow: Bool = defaultHasHeaderRow,
|
||||
delimiter: UnicodeScalar = defaultDelimiter)
|
||||
throws
|
||||
{
|
||||
let reader = try BinaryReader(stream: stream, endian: endian, closeOnDeinit: true)
|
||||
let iterator = UnicodeIterator(input: reader.makeUInt32Iterator(), inputEncodingType: codecType)
|
||||
try self.init(iterator: iterator, hasHeaderRow: hasHeaderRow, delimiter: delimiter)
|
||||
}
|
||||
|
||||
public func next() -> [String]? {
|
||||
fieldBuffer.length = 0
|
||||
// MARK: IteratorProtocol
|
||||
|
||||
/// Advances and returns the next element of the underlying sequence, or
|
||||
/// `nil` if no next element exists.
|
||||
///
|
||||
/// Repeatedly calling this method returns, in order, all the elements of the
|
||||
/// underlying sequence. After the sequence has run out of elements, the
|
||||
/// `next()` method returns `nil`.
|
||||
///
|
||||
/// You must not call this method if it has previously returned `nil` or if
|
||||
/// any other copy of this iterator has been advanced with a call to its
|
||||
/// `next()` method.
|
||||
///
|
||||
/// The following example shows how an iterator can be used explicitly to
|
||||
/// emulate a `for`-`in` loop. First, retrieve a sequence's iterator, and
|
||||
/// then call the iterator's `next()` method until it returns `nil`.
|
||||
///
|
||||
/// let numbers = [2, 3, 5, 7]
|
||||
/// var numbersIterator = numbers.makeIterator()
|
||||
///
|
||||
/// while let num = numbersIterator.next() {
|
||||
/// print(num)
|
||||
/// }
|
||||
/// // Prints "2"
|
||||
/// // Prints "3"
|
||||
/// // Prints "5"
|
||||
/// // Prints "7"
|
||||
///
|
||||
/// - Returns: The next element in the underlying sequence if a next element
|
||||
/// exists; otherwise, `nil`.
|
||||
public mutating func next() -> [String]? {
|
||||
return readRow()
|
||||
}
|
||||
|
||||
internal mutating func moveNext() -> UnicodeScalar? {
|
||||
if back != nil {
|
||||
defer { back = nil }
|
||||
return back
|
||||
}
|
||||
return iterator.next()
|
||||
}
|
||||
|
||||
internal mutating func readRow() -> [String]? {
|
||||
currentRow = nil
|
||||
|
||||
if closed {
|
||||
return nil
|
||||
}
|
||||
if lastReadCount <= 0 {
|
||||
var next = moveNext()
|
||||
if next == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var fields = [String]()
|
||||
|
||||
var fieldStart = bufferOffset
|
||||
var charLength = 0
|
||||
var escaping = false
|
||||
var quotationCount = 0
|
||||
|
||||
var prev: UInt32 = 0
|
||||
|
||||
var row = [String]()
|
||||
var field: String
|
||||
var end: Bool
|
||||
while true {
|
||||
if bufferOffset >= lastReadCount {
|
||||
if charLength > 0 {
|
||||
fieldBuffer.appendBytes(buffer + fieldStart, length: charWidth * charLength)
|
||||
if next == nil {
|
||||
(field, end) = ("", true)
|
||||
}
|
||||
bufferOffset = 0
|
||||
fieldStart = 0
|
||||
charLength = 0
|
||||
|
||||
lastReadCount = stream.read(buffer, maxLength: bufferSize)
|
||||
if lastReadCount < 0 {
|
||||
// bad end
|
||||
lastError = CSVError.StreamError
|
||||
return nil
|
||||
}
|
||||
if lastReadCount == 0 {
|
||||
// true end
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var c: UInt32 = 0
|
||||
|
||||
switch encoding {
|
||||
case NSUTF16BigEndianStringEncoding:
|
||||
let _c = ReadBigInt16(buffer, byteOffset: bufferOffset)
|
||||
c = UInt32(_c)
|
||||
|
||||
case NSUTF16LittleEndianStringEncoding:
|
||||
let _c = ReadLittleInt16(buffer, byteOffset: bufferOffset)
|
||||
c = UInt32(_c)
|
||||
|
||||
case NSUTF32BigEndianStringEncoding:
|
||||
c = ReadBigInt32(buffer, byteOffset: bufferOffset)
|
||||
|
||||
case NSUTF32LittleEndianStringEncoding:
|
||||
c = ReadLittleInt32(buffer, byteOffset: bufferOffset)
|
||||
|
||||
default: // multi-byte character encodings
|
||||
let _c = (buffer + bufferOffset)[0]
|
||||
c = UInt32(_c)
|
||||
}
|
||||
|
||||
if c == DQUOTE {
|
||||
quotationCount += 1
|
||||
}
|
||||
|
||||
if c == DQUOTE && charLength == 0 {
|
||||
escaping = true
|
||||
}
|
||||
|
||||
if escaping && prev == DQUOTE && (c == delimiter || c == CR || c == LF) && (quotationCount % 2 == 0) {
|
||||
escaping = false
|
||||
}
|
||||
|
||||
if !escaping && prev == CR && c != LF {
|
||||
fieldBuffer.appendBytes(buffer + fieldStart, length: charWidth * charLength)
|
||||
break
|
||||
}
|
||||
|
||||
prev = c
|
||||
bufferOffset += charWidth
|
||||
|
||||
if !escaping {
|
||||
if c == CR {
|
||||
continue
|
||||
}
|
||||
if c == LF {
|
||||
fieldBuffer.appendBytes(buffer + fieldStart, length: charWidth * charLength)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// フィールドの終わり
|
||||
if !escaping && c == delimiter {
|
||||
fieldBuffer.appendBytes(buffer + fieldStart, length: charWidth * charLength)
|
||||
|
||||
guard let field = getField(quotationCount) else {
|
||||
return nil
|
||||
}
|
||||
fields.append(field)
|
||||
|
||||
// reset
|
||||
fieldBuffer.length = 0
|
||||
quotationCount = 0
|
||||
charLength = 0
|
||||
|
||||
fieldStart = bufferOffset
|
||||
else if next == DQUOTE {
|
||||
(field, end) = readField(quoted: true)
|
||||
}
|
||||
else {
|
||||
charLength += 1
|
||||
back = next
|
||||
(field, end) = readField(quoted: false)
|
||||
}
|
||||
row.append(field)
|
||||
if end {
|
||||
break
|
||||
}
|
||||
next = moveNext()
|
||||
}
|
||||
|
||||
currentRow = row
|
||||
return row
|
||||
}
|
||||
|
||||
internal mutating func readField(quoted quoted: Bool) -> (String, Bool) {
|
||||
var field = ""
|
||||
|
||||
var next = moveNext()
|
||||
while let c = next {
|
||||
if quoted {
|
||||
if c == DQUOTE {
|
||||
let cNext = moveNext()
|
||||
if cNext == nil || cNext == CR || cNext == LF {
|
||||
if cNext == CR {
|
||||
let cNextNext = moveNext()
|
||||
if cNextNext != LF {
|
||||
back = cNextNext
|
||||
}
|
||||
}
|
||||
// END ROW
|
||||
return (field, true)
|
||||
}
|
||||
else if cNext == delimiter {
|
||||
// END FIELD
|
||||
return (field, false)
|
||||
}
|
||||
else if cNext == DQUOTE {
|
||||
// ESC
|
||||
field.append(DQUOTE)
|
||||
}
|
||||
else {
|
||||
// ERROR??
|
||||
field.append(c)
|
||||
}
|
||||
}
|
||||
else {
|
||||
field.append(c)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if c == CR || c == LF {
|
||||
if c == CR {
|
||||
let cNext = moveNext()
|
||||
if cNext != LF {
|
||||
back = cNext
|
||||
}
|
||||
}
|
||||
// END ROW
|
||||
return (field, true)
|
||||
}
|
||||
else if c == delimiter {
|
||||
// END FIELD
|
||||
return (field, false)
|
||||
}
|
||||
else {
|
||||
field.append(c)
|
||||
}
|
||||
}
|
||||
|
||||
guard let field = getField(quotationCount) else {
|
||||
return nil
|
||||
next = moveNext()
|
||||
}
|
||||
|
||||
// 最後の空行
|
||||
if isBufferEOF && fields.count == 0 && field.isEmpty {
|
||||
return nil
|
||||
}
|
||||
|
||||
fields.append(field)
|
||||
currentRow = fields
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// MARK: Utility
|
||||
|
||||
private var isBufferEOF: Bool {
|
||||
if stream.hasBytesAvailable {
|
||||
return false
|
||||
}
|
||||
return bufferOffset >= (lastReadCount - 1)
|
||||
}
|
||||
|
||||
private func getField(quotationCount: Int) -> String? {
|
||||
guard var field = String(data: fieldBuffer, encoding: encoding) else {
|
||||
lastError = CSVError.StringEncodingMismatch
|
||||
return nil
|
||||
}
|
||||
|
||||
if quotationCount >= 2
|
||||
&& field.hasPrefix("\"")
|
||||
&& field.hasSuffix("\"")
|
||||
{
|
||||
//let start = field.index(field.startIndex, offsetBy: 1)
|
||||
//let end = field.index(field.endIndex, offsetBy: -1)
|
||||
let start = field.startIndex.advancedBy(1)
|
||||
let end = field.endIndex.advancedBy(-1)
|
||||
field = field[start..<end]
|
||||
}
|
||||
|
||||
if quotationCount >= 4 {
|
||||
field = field.stringByReplacingOccurrencesOfString("\"\"", withString: "\"")
|
||||
}
|
||||
|
||||
return field
|
||||
return (field, true)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,15 +3,16 @@
|
|||
// CSV
|
||||
//
|
||||
// Created by Yasuhiro Hatta on 2016/06/11.
|
||||
//
|
||||
// Copyright © 2016 yaslab. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum CSVError: ErrorType {
|
||||
case ParameterError
|
||||
case StreamError
|
||||
case HeaderReadError
|
||||
case MemoryAllocationFailed
|
||||
case CannotOpenFile
|
||||
case CannotReadFile
|
||||
case StreamErrorHasOccurred(error: NSError)
|
||||
case CannotReadHeaderRow
|
||||
case StringEncodingMismatch
|
||||
case StringEndianMismatch
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// CSV
|
||||
//
|
||||
// Created by Yasuhiro Hatta on 2016/06/11.
|
||||
//
|
||||
// Copyright © 2016 yaslab. All rights reserved.
|
||||
//
|
||||
|
||||
@import Foundation;
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// Endian.swift
|
||||
// CSV
|
||||
//
|
||||
// Created by Yasuhiro Hatta on 2016/06/21.
|
||||
// Copyright © 2016 yaslab. All rights reserved.
|
||||
//
|
||||
|
||||
public enum Endian {
|
||||
case Big
|
||||
case Little
|
||||
case Unknown
|
||||
}
|
|
@ -15,7 +15,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.2.0</string>
|
||||
<string>0.3.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// UnicodeIterator.swift
|
||||
// CSV
|
||||
//
|
||||
// Created by Yasuhiro Hatta on 2016/06/20.
|
||||
// Copyright © 2016 yaslab. All rights reserved.
|
||||
//
|
||||
|
||||
internal struct UnicodeIterator<
|
||||
Input: GeneratorType,
|
||||
InputEncoding: UnicodeCodecType
|
||||
where InputEncoding.CodeUnit == Input.Element>
|
||||
: GeneratorType {
|
||||
|
||||
private var input: Input
|
||||
private var inputEncoding: InputEncoding
|
||||
|
||||
internal init(input: Input, inputEncodingType: InputEncoding.Type) {
|
||||
self.input = input
|
||||
self.inputEncoding = inputEncodingType.init()
|
||||
}
|
||||
|
||||
internal mutating func next() -> UnicodeScalar? {
|
||||
switch inputEncoding.decode(&input) {
|
||||
case .Result(let c): return c
|
||||
case .EmptyInput: return nil
|
||||
case .Error: return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -13,69 +13,60 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func test1Line() {
|
||||
let csv = "abab,cdcd,efef"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
|
||||
}
|
||||
|
||||
func testQuoted() {
|
||||
let csv = "abab,\"cdcd\",efef"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
|
||||
}
|
||||
|
||||
func testLF() {
|
||||
let csv = "abab,cdcd,efef\nzxcv,asdf,qwer"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qwer"])
|
||||
}
|
||||
|
||||
func testCommaInQuotationMarks() {
|
||||
let csv = "abab,\"cd,cd\",efef"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "cd,cd", "efef"])
|
||||
}
|
||||
|
||||
func testCRLF() {
|
||||
let csv = "abab,cdcd,efef\r\nzxcv,asdf,qwer"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qwer"])
|
||||
}
|
||||
|
||||
func testEscapedQuotationMark() {
|
||||
func testEscapedQuotationMark1() {
|
||||
let csv = "abab,\"\"\"cdcd\",efef\r\nzxcv,asdf,qwer"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "\"cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qwer"])
|
||||
}
|
||||
|
||||
func testQuotationMark2() {
|
||||
func testEscapedQuotationMark2() {
|
||||
let csv = "abab,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\""
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er"])
|
||||
}
|
||||
|
||||
func testEmptyField() {
|
||||
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
}
|
||||
|
||||
func testLastCR() {
|
||||
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\",\r"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records.count, 2)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
|
@ -83,8 +74,7 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testLastCRLF() {
|
||||
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\",\r\n"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records.count, 2)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
|
@ -92,8 +82,7 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testLastLF() {
|
||||
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\",\n"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records.count, 2)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
|
@ -101,8 +90,7 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testLFInQuotationMarks() {
|
||||
let csv = "abab,,\"\rcdcd\n\",efef\r\nzxcv,asdf,\"qw\"\"er\",\n"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records.count, 2)
|
||||
XCTAssertEqual(records[0], ["abab", "", "\rcdcd\n", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
|
@ -110,8 +98,7 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testLineBreakLF() {
|
||||
let csv = "qwe,asd\nzxc,rty"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records.count, 2)
|
||||
XCTAssertEqual(records[0], ["qwe", "asd"])
|
||||
XCTAssertEqual(records[1], ["zxc", "rty"])
|
||||
|
@ -119,8 +106,7 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testLineBreakCR() {
|
||||
let csv = "qwe,asd\rzxc,rty"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records.count, 2)
|
||||
XCTAssertEqual(records[0], ["qwe", "asd"])
|
||||
XCTAssertEqual(records[1], ["zxc", "rty"])
|
||||
|
@ -128,8 +114,7 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testLineBreakCRLF() {
|
||||
let csv = "qwe,asd\r\nzxc,rty"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records.count, 2)
|
||||
XCTAssertEqual(records[0], ["qwe", "asd"])
|
||||
XCTAssertEqual(records[1], ["zxc", "rty"])
|
||||
|
@ -137,8 +122,7 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testLineBreakLFLF() {
|
||||
let csv = "qwe,asd\n\nzxc,rty"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records.count, 3)
|
||||
XCTAssertEqual(records[0], ["qwe", "asd"])
|
||||
XCTAssertEqual(records[1], [""])
|
||||
|
@ -147,8 +131,7 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testLineBreakCRCR() {
|
||||
let csv = "qwe,asd\r\rzxc,rty"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records.count, 3)
|
||||
XCTAssertEqual(records[0], ["qwe", "asd"])
|
||||
XCTAssertEqual(records[1], [""])
|
||||
|
@ -157,119 +140,130 @@ class CSVReaderTests: XCTestCase {
|
|||
|
||||
func testLineBreakCRLFCRLF() {
|
||||
let csv = "qwe,asd\r\n\r\nzxc,rty"
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
let records = parse(csv: csv)
|
||||
XCTAssertEqual(records.count, 3)
|
||||
XCTAssertEqual(records[0], ["qwe", "asd"])
|
||||
XCTAssertEqual(records[1], [""])
|
||||
XCTAssertEqual(records[2], ["zxc", "rty"])
|
||||
}
|
||||
|
||||
func testEncodingWithoutBOM() {
|
||||
var index = 0
|
||||
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
for encoding in allEncodings() {
|
||||
print("index: \(index)")
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
index += 1
|
||||
}
|
||||
}
|
||||
// func testEncodingWithoutBOM() {
|
||||
// var index = 0
|
||||
// let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
// for encoding in allEncodings() {
|
||||
// print("index: \(index)")
|
||||
// let records = parse(csv: csv, encoding: encoding)
|
||||
// XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
// XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
// index += 1
|
||||
// }
|
||||
// }
|
||||
|
||||
func testUTF8WithBOM() {
|
||||
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let csvString = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF8StringEncoding
|
||||
let mutableData = NSMutableData()
|
||||
var mutableData = NSMutableData()
|
||||
mutableData.appendBytes(utf8BOM, length: utf8BOM.count)
|
||||
mutableData.appendData(csv.dataUsingEncoding(encoding)!)
|
||||
let records = parseData(mutableData, encoding: encoding)
|
||||
mutableData.appendData(csvString.dataUsingEncoding(encoding)!)
|
||||
let stream = NSInputStream(data: mutableData)
|
||||
let csv = try! CSV(stream: stream, codecType: UTF8.self)
|
||||
let records = getRecords(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
}
|
||||
|
||||
func testUTF16WithNativeEndianBOM() {
|
||||
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let csvString = "abab,,cdcd,efef\r\nzxcv,😆asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF16StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
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 records = getRecords(csv: csv)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
XCTAssertEqual(records[1], ["zxcv", "😆asdf", "qw\"er", ""])
|
||||
}
|
||||
|
||||
func testUTF16WithBigEndianBOM() {
|
||||
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF16StringEncoding
|
||||
let mutableData = NSMutableData()
|
||||
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(csv.dataUsingEncoding(NSUTF16BigEndianStringEncoding)!)
|
||||
let records = parseData(mutableData, encoding: encoding)
|
||||
mutableData.appendData(csvString.dataUsingEncoding(encoding)!)
|
||||
let stream = NSInputStream(data: mutableData)
|
||||
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", ""])
|
||||
XCTAssertEqual(records[1], ["😆zxcv", "asdf", "qw\"er", ""])
|
||||
}
|
||||
|
||||
func testUTF16WithLittleEndianBOM() {
|
||||
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF16StringEncoding
|
||||
let mutableData = NSMutableData()
|
||||
let csvString = "abab,,cdcd,efef\r\nzxcv😆,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF16LittleEndianStringEncoding
|
||||
var mutableData = NSMutableData()
|
||||
mutableData.appendBytes(utf16LittleEndianBOM, length: utf16LittleEndianBOM.count)
|
||||
mutableData.appendData(csv.dataUsingEncoding(NSUTF16LittleEndianStringEncoding)!)
|
||||
let records = parseData(mutableData, encoding: encoding)
|
||||
mutableData.appendData(csvString.dataUsingEncoding(encoding)!)
|
||||
let stream = NSInputStream(data: mutableData)
|
||||
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", ""])
|
||||
XCTAssertEqual(records[1], ["zxcv😆", "asdf", "qw\"er", ""])
|
||||
}
|
||||
|
||||
func testUTF32WithNativeEndianBOM() {
|
||||
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let csvString = "😆abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF32StringEncoding
|
||||
let records = parseCSV(csv, encoding: encoding)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
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 records = getRecords(csv: csv)
|
||||
XCTAssertEqual(records[0], ["😆abab", "", "cdcd", "efef"])
|
||||
XCTAssertEqual(records[1], ["zxcv", "asdf", "qw\"er", ""])
|
||||
}
|
||||
|
||||
func testUTF32WithBigEndianBOM() {
|
||||
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF32StringEncoding
|
||||
let mutableData = NSMutableData()
|
||||
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(csv.dataUsingEncoding(NSUTF32BigEndianStringEncoding)!)
|
||||
let records = parseData(mutableData, encoding: encoding)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
mutableData.appendData(csvString.dataUsingEncoding(encoding)!)
|
||||
let stream = NSInputStream(data: mutableData)
|
||||
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", ""])
|
||||
}
|
||||
|
||||
func testUTF32WithLittleEndianBOM() {
|
||||
let csv = "abab,,cdcd,efef\r\nzxcv,asdf,\"qw\"\"er\","
|
||||
let encoding = NSUTF32StringEncoding
|
||||
let mutableData = NSMutableData()
|
||||
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(csv.dataUsingEncoding(NSUTF32LittleEndianStringEncoding)!)
|
||||
let records = parseData(mutableData, encoding: encoding)
|
||||
XCTAssertEqual(records[0], ["abab", "", "cdcd", "efef"])
|
||||
mutableData.appendData(csvString.dataUsingEncoding(encoding)!)
|
||||
let stream = NSInputStream(data: mutableData)
|
||||
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", ""])
|
||||
}
|
||||
|
||||
func allEncodings() -> [NSStringEncoding] {
|
||||
return [
|
||||
// multi-byte character encodings
|
||||
NSShiftJISStringEncoding,
|
||||
NSJapaneseEUCStringEncoding,
|
||||
NSUTF8StringEncoding,
|
||||
// wide character encodings
|
||||
NSUTF16BigEndianStringEncoding,
|
||||
NSUTF16LittleEndianStringEncoding,
|
||||
NSUTF32BigEndianStringEncoding,
|
||||
NSUTF32LittleEndianStringEncoding,
|
||||
]
|
||||
}
|
||||
// func allEncodings() -> [String.Encoding] {
|
||||
// return [
|
||||
// // multi-byte character encodings
|
||||
// //String.Encoding.shiftJIS,
|
||||
// //String.Encoding.japaneseEUC,
|
||||
// String.Encoding.utf8,
|
||||
// // wide character encodings
|
||||
// String.Encoding.utf16BigEndian,
|
||||
// String.Encoding.utf16LittleEndian,
|
||||
// String.Encoding.utf32BigEndian,
|
||||
// String.Encoding.utf32LittleEndian,
|
||||
// ]
|
||||
// }
|
||||
|
||||
func parseCSV(csv: String, encoding: NSStringEncoding) -> [[String]] {
|
||||
let data = csv.dataUsingEncoding(encoding)!
|
||||
return parseData(data, encoding: encoding)
|
||||
}
|
||||
|
||||
func parseData(data: NSData, encoding: NSStringEncoding) -> [[String]] {
|
||||
let stream = NSInputStream(data: data)
|
||||
let reader = try! CSV(stream: stream, encoding: encoding)
|
||||
func parse(csv csv: String) -> [[String]] {
|
||||
let reader = try! CSV(string: csv)
|
||||
var records = [[String]]()
|
||||
for row in reader {
|
||||
records.append(row)
|
||||
|
@ -277,6 +271,29 @@ class CSVReaderTests: XCTestCase {
|
|||
return records
|
||||
}
|
||||
|
||||
func getRecords(csv csv: CSV) -> [[String]] {
|
||||
var records = [[String]]()
|
||||
for row in csv {
|
||||
records.append(row)
|
||||
}
|
||||
return records
|
||||
}
|
||||
|
||||
// func parse(csv: String, encoding: String.Encoding) -> [[String]] {
|
||||
// let data = csv.data(using: encoding)!
|
||||
// return parse(data: data, encoding: encoding)
|
||||
// }
|
||||
//
|
||||
// func parse(data: Data, encoding: String.Encoding) -> [[String]] {
|
||||
// let stream = InputStream(data: data)
|
||||
// let reader = try! CSV(stream: stream, encoding: encoding)
|
||||
// var records = [[String]]()
|
||||
// for row in reader {
|
||||
// records.append(row)
|
||||
// }
|
||||
// return records
|
||||
// }
|
||||
|
||||
static var allTests : [(String, (CSVReaderTests) -> () throws -> Void)] {
|
||||
return [
|
||||
//("testExample1", testExample1),
|
||||
|
|
|
@ -97,53 +97,53 @@ class CSVTests: XCTestCase {
|
|||
XCTAssertEqual(i, 3)
|
||||
}
|
||||
|
||||
func testBufferSizeMod0() {
|
||||
let csvString = "0,1,2,3,4,5,6,7,8,9\n"
|
||||
let csv = try! CSV(string: csvString, bufferSize: 12)
|
||||
XCTAssertEqual(csv.bufferSize, 12)
|
||||
}
|
||||
|
||||
func testBufferSizeMod1() {
|
||||
let csvString = "0,1,2,3,4,5,6,7,8,9\n"
|
||||
let csv = try! CSV(string: csvString, bufferSize: 13)
|
||||
XCTAssertEqual(csv.bufferSize, 16)
|
||||
}
|
||||
|
||||
func testBufferSizeMod2() {
|
||||
let csvString = "0,1,2,3,4,5,6,7,8,9\n"
|
||||
let csv = try! CSV(string: csvString, bufferSize: 14)
|
||||
XCTAssertEqual(csv.bufferSize, 16)
|
||||
}
|
||||
|
||||
func testBufferSizeMod3() {
|
||||
let csvString = "0,1,2,3,4,5,6,7,8,9\n"
|
||||
let csv = try! CSV(string: csvString, bufferSize: 15)
|
||||
XCTAssertEqual(csv.bufferSize, 16)
|
||||
}
|
||||
|
||||
func testBufferSizeMod4() {
|
||||
let csvString = "0,1,2,3,4,5,6,7,8,9\n"
|
||||
let csv = try! CSV(string: csvString, bufferSize: 16)
|
||||
XCTAssertEqual(csv.bufferSize, 16)
|
||||
}
|
||||
|
||||
func testBigDataAndSmallBufferSize() {
|
||||
let line = "0,1,2,3,4,5,6,7,8,9\n"
|
||||
var csv = ""
|
||||
for _ in 0..<10000 {
|
||||
csv += line
|
||||
}
|
||||
var i = 0
|
||||
for row in try! CSV(string: csv, bufferSize: 10) {
|
||||
XCTAssertEqual(row, ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"])
|
||||
i += 1
|
||||
}
|
||||
XCTAssertEqual(i, 10000)
|
||||
}
|
||||
// func testBufferSizeMod0() {
|
||||
// let csvString = "0,1,2,3,4,5,6,7,8,9\n"
|
||||
// let csv = try! CSV(string: csvString, bufferSize: 12)
|
||||
// XCTAssertEqual(csv.bufferSize, 12)
|
||||
// }
|
||||
//
|
||||
// func testBufferSizeMod1() {
|
||||
// let csvString = "0,1,2,3,4,5,6,7,8,9\n"
|
||||
// let csv = try! CSV(string: csvString, bufferSize: 13)
|
||||
// XCTAssertEqual(csv.bufferSize, 16)
|
||||
// }
|
||||
//
|
||||
// func testBufferSizeMod2() {
|
||||
// let csvString = "0,1,2,3,4,5,6,7,8,9\n"
|
||||
// let csv = try! CSV(string: csvString, bufferSize: 14)
|
||||
// XCTAssertEqual(csv.bufferSize, 16)
|
||||
// }
|
||||
//
|
||||
// func testBufferSizeMod3() {
|
||||
// let csvString = "0,1,2,3,4,5,6,7,8,9\n"
|
||||
// let csv = try! CSV(string: csvString, bufferSize: 15)
|
||||
// XCTAssertEqual(csv.bufferSize, 16)
|
||||
// }
|
||||
//
|
||||
// func testBufferSizeMod4() {
|
||||
// let csvString = "0,1,2,3,4,5,6,7,8,9\n"
|
||||
// let csv = try! CSV(string: csvString, bufferSize: 16)
|
||||
// XCTAssertEqual(csv.bufferSize, 16)
|
||||
// }
|
||||
//
|
||||
// func testBigDataAndSmallBufferSize() {
|
||||
// let line = "0,1,2,3,4,5,6,7,8,9\n"
|
||||
// var csv = ""
|
||||
// for _ in 0..<10000 {
|
||||
// csv += line
|
||||
// }
|
||||
// var i = 0
|
||||
// for row in try! CSV(string: csv, bufferSize: 10) {
|
||||
// XCTAssertEqual(row, ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"])
|
||||
// i += 1
|
||||
// }
|
||||
// XCTAssertEqual(i, 10000)
|
||||
// }
|
||||
|
||||
func testSubscript() {
|
||||
let csvString = "id,name\n001,hoge\n002,fuga"
|
||||
let csv = try! CSV(string: csvString, hasHeaderRow: true)
|
||||
var csv = try! CSV(string: csvString, hasHeaderRow: true)
|
||||
var i = 0
|
||||
while csv.next() != nil {
|
||||
switch i {
|
||||
|
@ -161,4 +161,18 @@ class CSVTests: XCTestCase {
|
|||
XCTAssertEqual(i, 2)
|
||||
}
|
||||
|
||||
func testCSVState1() {
|
||||
let it = "あ,い1,\"う\",えお\n,,x,".unicodeScalars.generate()
|
||||
var csv = try! CSV(iterator: it, hasHeaderRow: defaultHasHeaderRow, delimiter: defaultDelimiter)
|
||||
|
||||
var rows = [[String]]()
|
||||
|
||||
while let row = csv.next() {
|
||||
rows.append(row)
|
||||
}
|
||||
XCTAssertEqual(rows.count, 2)
|
||||
XCTAssertEqual(rows[0], ["あ", "い1", "う", "えお"])
|
||||
XCTAssertEqual(rows[1], ["", "", "x", ""])
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,8 @@ class ReadmeTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testFromFilePath() {
|
||||
//for row in try! CSV(path: "/path/to/file.csv") {
|
||||
// let stream = NSInputStream(fileAtPath: "/path/to/file.csv")!
|
||||
// for row in try! CSV(stream: stream) {
|
||||
// print("\(row)")
|
||||
// }
|
||||
}
|
||||
|
@ -41,7 +42,7 @@ class ReadmeTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testGetTheFieldValueUsingSubscript() {
|
||||
let csv = try! CSV(
|
||||
var csv = try! CSV(
|
||||
string: "id,name\n1,foo",
|
||||
hasHeaderRow: true) // It must be true.
|
||||
|
||||
|
@ -53,8 +54,9 @@ class ReadmeTests: XCTestCase {
|
|||
|
||||
func testProvideTheCharacterEncoding() {
|
||||
// let csv = try! CSV(
|
||||
// path: "/path/to/file.csv",
|
||||
// encoding: NSUTF8StringEncoding)
|
||||
// stream: NSInputStream(fileAtPath: "/path/to/file.csv")!,
|
||||
// codecType: UTF16.self,
|
||||
// endian: .Big)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue