2 Commits da3d2b2113 ... f485ca8202

Author SHA1 Message Date
  zhudongyong f485ca8202 文档 - 参数配置 自动化控制规则 文档 1 year ago
  zhudongyong 6c565ce226 功能 - RTF 支持纯字符对比功能 1 year ago
43 changed files with 873 additions and 524 deletions
  1. 8 4
      KdanAutoTest/KdanAuto.xcodeproj/project.pbxproj
  2. BIN
      KdanAutoTest/KdanAuto.xcodeproj/project.xcworkspace/xcuserdata/zhudongyong.xcuserdatad/UserInterfaceState.xcuserstate
  3. 13 1
      KdanAutoTest/KdanAuto/Class/AdvanceSettingViewController/AdvanceSettingPropertyRules.plist
  4. 330 0
      KdanAutoTest/KdanAuto/Class/AutoTestCase/StringAutoBackTest.swift
  5. 0 516
      KdanAutoTest/KdanAuto/Class/AutoTestCase/StringAutoCompare.swift
  6. 192 0
      KdanAutoTest/KdanAuto/Class/AutoTestCase/StringAutoCompareTest.swift
  7. 12 3
      KdanAutoTest/KdanAuto/Class/AutoTestCase/StringAutoTest.swift
  8. BIN
      PropertySettingGuide.pdf
  9. BIN
      PropertySettingGuide/KdanAuto 参数规则控制流程.png
  10. BIN
      PropertySettingGuide/OCR.language.params.png
  11. 318 0
      PropertySettingGuide/PropertySettingGuide.md
  12. BIN
      PropertySettingGuide/all.extention.png
  13. BIN
      PropertySettingGuide/csv.params.png
  14. BIN
      PropertySettingGuide/csv.png
  15. BIN
      PropertySettingGuide/csv.property.png
  16. BIN
      PropertySettingGuide/excel.params.png
  17. BIN
      PropertySettingGuide/excel.png
  18. BIN
      PropertySettingGuide/excel.property.png
  19. BIN
      PropertySettingGuide/html.params.png
  20. BIN
      PropertySettingGuide/html.png
  21. BIN
      PropertySettingGuide/html.property.png
  22. BIN
      PropertySettingGuide/jpeg.params.png
  23. BIN
      PropertySettingGuide/jpeg.png
  24. BIN
      PropertySettingGuide/jpeg.property.png
  25. BIN
      PropertySettingGuide/pdf.png
  26. BIN
      PropertySettingGuide/pdf.property.png
  27. BIN
      PropertySettingGuide/png.png
  28. BIN
      PropertySettingGuide/png.property.png
  29. BIN
      PropertySettingGuide/ppt.params.png
  30. BIN
      PropertySettingGuide/ppt.png
  31. BIN
      PropertySettingGuide/ppt.property.png
  32. BIN
      PropertySettingGuide/rtf.class.png
  33. BIN
      PropertySettingGuide/rtf.params.png
  34. BIN
      PropertySettingGuide/rtf.png
  35. BIN
      PropertySettingGuide/rtf.property.png
  36. BIN
      PropertySettingGuide/txt.params.png
  37. BIN
      PropertySettingGuide/txt.png
  38. BIN
      PropertySettingGuide/txt.property.png
  39. BIN
      PropertySettingGuide/word.class.png
  40. BIN
      PropertySettingGuide/word.params.png
  41. BIN
      PropertySettingGuide/word.png
  42. BIN
      PropertySettingGuide/word.property.png
  43. BIN
      Use Guide.zip

+ 8 - 4
KdanAutoTest/KdanAuto.xcodeproj/project.pbxproj

@@ -66,7 +66,7 @@
 		24848DDF29EF74AD002A7ED5 /* LogViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 24848DDD29EF74AD002A7ED5 /* LogViewController.xib */; };
 		24848DE229EFCE63002A7ED5 /* CDoucumnetAIResource.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 24848DE129EFCE63002A7ED5 /* CDoucumnetAIResource.bundle */; };
 		24848DE429EFD0DF002A7ED5 /* Vision.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24848DE329EFD0DF002A7ED5 /* Vision.framework */; };
-		24848DE629F2A9E4002A7ED5 /* StringAutoCompare.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24848DE529F2A9E3002A7ED5 /* StringAutoCompare.swift */; };
+		24848DE629F2A9E4002A7ED5 /* StringAutoCompareTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24848DE529F2A9E3002A7ED5 /* StringAutoCompareTest.swift */; };
 		24A6FF49293091E000B34F2E /* AutoTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A6FF48293091E000B34F2E /* AutoTest.swift */; };
 		24A6FF4B2930939D00B34F2E /* TextColorAutoTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A6FF4A2930939D00B34F2E /* TextColorAutoTest.swift */; };
 		24A6FF4F2930A1E100B34F2E /* FontAutoTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A6FF4E2930A1E100B34F2E /* FontAutoTest.swift */; };
@@ -108,6 +108,7 @@
 		24DCE8B529506CDE004EBA35 /* AutoTestProperty.plist in Resources */ = {isa = PBXBuildFile; fileRef = 24DCE8B429506CDE004EBA35 /* AutoTestProperty.plist */; };
 		24DCE8BB29518FD3004EBA35 /* ProcessThumbnal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 240509B62943479800B501B2 /* ProcessThumbnal.swift */; };
 		24E3165D29DC35A20009E358 /* UpdateSDK.sh in Resources */ = {isa = PBXBuildFile; fileRef = 24E3165C29DC35A20009E358 /* UpdateSDK.sh */; };
+		24E8AE3B29F6A4A900988963 /* StringAutoBackTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E8AE3A29F6A4A900988963 /* StringAutoBackTest.swift */; };
 		24FE3FF329BAF9B8004F4DD4 /* CoreImage.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24FE3FF229BAF9B8004F4DD4 /* CoreImage.framework */; };
 /* End PBXBuildFile section */
 
@@ -223,7 +224,7 @@
 		24848DDD29EF74AD002A7ED5 /* LogViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LogViewController.xib; sourceTree = "<group>"; };
 		24848DE129EFCE63002A7ED5 /* CDoucumnetAIResource.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = CDoucumnetAIResource.bundle; sourceTree = "<group>"; };
 		24848DE329EFD0DF002A7ED5 /* Vision.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vision.framework; path = System/Library/Frameworks/Vision.framework; sourceTree = SDKROOT; };
-		24848DE529F2A9E3002A7ED5 /* StringAutoCompare.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringAutoCompare.swift; sourceTree = "<group>"; };
+		24848DE529F2A9E3002A7ED5 /* StringAutoCompareTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringAutoCompareTest.swift; sourceTree = "<group>"; };
 		24A6FF48293091E000B34F2E /* AutoTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoTest.swift; sourceTree = "<group>"; };
 		24A6FF4A2930939D00B34F2E /* TextColorAutoTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextColorAutoTest.swift; sourceTree = "<group>"; };
 		24A6FF4E2930A1E100B34F2E /* FontAutoTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontAutoTest.swift; sourceTree = "<group>"; };
@@ -274,6 +275,7 @@
 		24DCE8B22950543C004EBA35 /* AutoTestCellInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoTestCellInfo.swift; sourceTree = "<group>"; };
 		24DCE8B429506CDE004EBA35 /* AutoTestProperty.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = AutoTestProperty.plist; sourceTree = "<group>"; };
 		24E3165C29DC35A20009E358 /* UpdateSDK.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = UpdateSDK.sh; sourceTree = "<group>"; };
+		24E8AE3A29F6A4A900988963 /* StringAutoBackTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringAutoBackTest.swift; sourceTree = "<group>"; };
 		24FE3FF229BAF9B8004F4DD4 /* CoreImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreImage.framework; path = System/Library/Frameworks/CoreImage.framework; sourceTree = SDKROOT; };
 /* End PBXFileReference section */
 
@@ -530,7 +532,8 @@
 				24A6FF48293091E000B34F2E /* AutoTest.swift */,
 				246FE590299DCFC400706586 /* PDFCompareTest.swift */,
 				24D7000A292D16BB00DAB5EE /* StringAutoTest.swift */,
-				24848DE529F2A9E3002A7ED5 /* StringAutoCompare.swift */,
+				24E8AE3A29F6A4A900988963 /* StringAutoBackTest.swift */,
+				24848DE529F2A9E3002A7ED5 /* StringAutoCompareTest.swift */,
 				24A6FF4A2930939D00B34F2E /* TextColorAutoTest.swift */,
 				24A6FF4E2930A1E100B34F2E /* FontAutoTest.swift */,
 			);
@@ -960,7 +963,7 @@
 				24DCE8AD295046E7004EBA35 /* TestFileTypeCellView.swift in Sources */,
 				246FE591299DCFC400706586 /* PDFCompareTest.swift in Sources */,
 				24D7FFFE292B509000DAB5EE /* DataModel.swift in Sources */,
-				24848DE629F2A9E4002A7ED5 /* StringAutoCompare.swift in Sources */,
+				24848DE629F2A9E4002A7ED5 /* StringAutoCompareTest.swift in Sources */,
 				24CA2337298FD6BE00038E10 /* ImageCompareCellView.swift in Sources */,
 				24848DDA29EEBCBC002A7ED5 /* ASSizePropertyCell.swift in Sources */,
 				24D7FF9B29261A6400DAB5EE /* AppDelegate.swift in Sources */,
@@ -983,6 +986,7 @@
 				246FE5A3299E0FCD00706586 /* zip.c in Sources */,
 				24DCE8B1295047D8004EBA35 /* TestFileCellView.swift in Sources */,
 				24A6FF4B2930939D00B34F2E /* TextColorAutoTest.swift in Sources */,
+				24E8AE3B29F6A4A900988963 /* StringAutoBackTest.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

BIN
KdanAutoTest/KdanAuto.xcodeproj/project.xcworkspace/xcuserdata/zhudongyong.xcuserdatad/UserInterfaceState.xcuserstate


+ 13 - 1
KdanAutoTest/KdanAuto/Class/AdvanceSettingViewController/AdvanceSettingPropertyRules.plist

@@ -57,6 +57,12 @@
 				<key>Class</key>
 				<string>StringAutoTest</string>
 			</dict>
+			<dict>
+				<key>Name</key>
+				<string>跨平台字符对比测试</string>
+				<key>Class</key>
+				<string>StringAutoCompareTest</string>
+			</dict>
 		</array>
 		<key>Params</key>
 		<array>
@@ -2192,11 +2198,17 @@
 				<key>Class</key>
 				<string>StringAutoTest</string>
 			</dict>
+			<dict>
+				<key>Name</key>
+				<string>字符逆序对比测试</string>
+				<key>Class</key>
+				<string>StringAutoBackTest</string>
+			</dict>
 			<dict>
 				<key>Name</key>
 				<string>跨平台字符对比测试</string>
 				<key>Class</key>
-				<string>StringAutoCompare</string>
+				<string>StringAutoCompareTest</string>
 			</dict>
 		</array>
 		<key>Extention</key>

+ 330 - 0
KdanAutoTest/KdanAuto/Class/AutoTestCase/StringAutoBackTest.swift

@@ -0,0 +1,330 @@
+//
+//  CharacterAutoTest.swift
+//  KdanAuto
+//
+//  Created by 朱东勇 on 2022/11/22.
+//
+
+import Foundation
+import Cocoa
+
+class StringAutoBackTest : StringAutoTest {
+    
+    
+    override func needTest() -> Bool {
+        return self.selectedKeys().count > 0
+    }
+    
+    
+    override class func shared() -> AutoTest? {
+        return StringAutoBackTest()
+    }
+    
+//    // Auto Test refrence Check File
+//    override func autoTest(_ complention:@escaping (_ object:AutoTest, _ report:NSAttributedString?) -> ()) {
+//        self.compareFinishedFiles.removeAllObjects();
+//        self.convertFiles.removeAllObjects()
+//
+//        clearCacheFiles()
+//
+//        let needCheckString = self.selectedKeys().contains("字符")
+//
+//        if !needCheckString {
+//            _status = .Finished
+//            complention(self, self.reportString)
+//            return
+//        }
+//
+//        _status = .Process
+//        reportString = NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】字符比对开始!\n",
+//                                                      attributes:[.foregroundColor : NSColor.blue])
+//        let files = DataModel.shared.originFilesFor(_fileType, type: _type)
+//        self.testFiles = NSArray(array: files);
+//
+//        let checkDirectory = self.checkFileDirectory()
+//        let originDirectory = self.originFileDirectory()
+//        let resultDirectory = self.resultFileDirectory()
+//
+//        if (files.count > 0) {
+//            try? FileManager.default.createDirectory(atPath: checkDirectory, withIntermediateDirectories: true);
+//            try? FileManager.default.createDirectory(atPath: resultDirectory, withIntermediateDirectories: true);
+//        }
+//
+//        var tDegree = Double(0);
+//        var tCount = Int(0)
+//        var fileIndex = 0;
+//
+//        var convertFileBlock = { (files:[String]) in }
+//        convertFileBlock = { (files:[String]) in
+//            if (fileIndex >= files.count) {
+//                TestDegreeManager.shared().set(((tCount != 0) ? tDegree/Double(tCount) : 0.0),
+//                                               fileType: self.fileType(),
+//                                               type: self.type())
+//
+//                self._status = .Finished
+//                DispatchQueue.main.async {
+//                    autoreleasepool {
+//                        complention(self, self.reportString);
+//                    }
+//                }
+//                return
+//            }
+//
+//            let fileName = files[fileIndex]
+//            let fName = NSString(string: fileName).deletingPathExtension
+//            let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf")
+//            let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+self.extention())
+//            let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+self.extention())
+//
+//
+//            self.reportString?.append(NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】开始转换文件 \"\(fName)\"\n",
+//                                                                     attributes:[.foregroundColor : NSColor.black]))
+//            // ...
+//            // 执行转换过程
+//            let index = self.testFiles.index(of: fileName);
+//            if (index != NSNotFound) {
+//                self.convertProgress = Double(index) / Double(self.testFiles.count)
+//            }
+//            self.convertFiles.add(fileName);
+//            self.testlog("开始转换:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
+//            self.process(originPath, resultPath: resultPath) { status in
+//                if FileManager.default.fileExists(atPath: resultPath) && status == 1 {
+//                    if needCheckString && FileManager.default.fileExists(atPath: checkPath) {
+//                        DispatchQueue.global().async {
+//                            let checkString = self.readTextFile(checkPath as NSString)
+//                            let resultStr = self.readTextFile(resultPath as NSString)
+//
+//                            if (checkString != nil && resultStr != nil) {
+//                                let maxSize = checkString!.count
+//                                let report = NSMutableAttributedString(string: "")
+//                                let degree = self.compareString(checkString as! NSString, result: resultStr as! NSString) { appAttr in
+//                                    report.append(appAttr)
+//                                }
+//                                //                                let degree = self.compareString(checkString as! NSString, result: resultStr as! NSString) { skipString, failString in
+//                                //                                    self.appendErrorInfo(skipString, failString: failString)
+//                                //                                }
+//
+//                                var color = NSColor.black
+//                                if fabs(degree-100.0) >= 0.01 {
+//                                    color = NSColor.red
+//                                }
+//                                tDegree += degree;
+//                                tCount += 1
+//
+//                                TestDegreeManager.shared().set(degree,
+//                                                               fileType: self.fileType(),
+//                                                               type: self.type(),
+//                                                               fileName: fileName)
+//
+//                                let successCount = Int(maxSize * Int(degree)/100)
+//                                report.append(NSAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"比对完成,准确率\(degree)%(\(successCount)/\(maxSize))\n",
+//                                                                      attributes:[.foregroundColor : color]))
+//                                if (report != nil) {
+//                                    do {
+//                                        let rtfData = try? report.data(from: .init(location: 0, length: report.length),
+//                                                                       documentAttributes: [.documentType: NSAttributedString.DocumentType.rtf])
+//
+//                                        let path = NSString(string: resultPath).appendingPathExtension("rtf")
+//                                        try? FileManager.default.removeItem(atPath: path!);
+//                                        try? rtfData?.write(to: NSURL.fileURL(withPath: path!))
+//                                    } catch {
+//                                    }
+//                                    self.reportString?.append(report)
+//                                }
+//                            }
+//
+//                            let index = self.testFiles.index(of: fileName);
+//                            if (index != NSNotFound) {
+//                                self.compareProgress = Double(index) / Double(self.testFiles.count)
+//                            }
+//                            self.compareFinishedFiles.add(fileName);
+//                            self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
+//
+//                            fileIndex += 1
+//                            convertFileBlock(files);
+//                        }
+//                    }else {
+//                        self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】对照文件 \"\(fName)\"不存在!\n",
+//                                                                                 attributes:[.foregroundColor : NSColor.red]))
+//
+//                        let index = self.testFiles.index(of: fileName);
+//                        if (index != NSNotFound) {
+//                            self.compareProgress = Double(index) / Double(self.testFiles.count)
+//                        }
+//                        self.compareFinishedFiles.add(fileName);
+//                        self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
+//
+//                        fileIndex += 1
+//                        convertFileBlock(files);
+//                    }
+//                }else {
+//                    if (status == 0) {
+//                        self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档失败!\n",
+//                                                                                 attributes:[.foregroundColor : NSColor.red]))
+//                    }else if (status == -1 || status == -2) {
+//                        self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"文档无法打开!\n",
+//                                                                                 attributes:[.foregroundColor : NSColor.red]))
+//                    }else if (status == -3) {
+//                        self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档中 Crash!\n",
+//                                                                                 attributes:[.foregroundColor : NSColor.red]))
+//                    }
+//
+//                    let index = self.testFiles.index(of: fileName);
+//                    if (index != NSNotFound) {
+//                        self.compareProgress = Double(index) / Double(self.testFiles.count)
+//                    }
+//                    self.compareFinishedFiles.add(fileName);
+//                    self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
+//                    fileIndex += 1
+//                    convertFileBlock(files);
+//                }
+//            }
+//        }
+//        convertFileBlock(files);
+//    }
+//
+//
+    /// Compare
+    override func compareString(_ check:NSString, result:NSString, callback:@escaping (_ appAttr:NSAttributedString)->()) -> Double {
+//    func compareString(_ check:NSString, result:NSString, failure:@escaping (_ skipString:NSString, _ failString:NSString)->()) -> Double {
+        return autoreleasepool {
+            var checkString = check
+            var resultStr = result
+            let maxSize = checkString.length
+            var successCount = 0;
+            /**
+             (A0 = B0)
+             - A-1 & B-1
+             (A0 != B0) & (A0 in B) & (B0 in A)
+             - 取 A0,B0最小 Range 值
+             - 字符串裁剪对齐
+             (A0 != B0) & (A0 in B)
+             - 存储B0到识别错误缓存
+             (A0 != B0) & (B0 in A)
+             - 存储 A0到识别遗漏字符串
+             (A0 != B0)
+             - 分别存储 A0、B0到遗漏及错误字串
+             */
+            var skipString = NSString()
+            var failString = NSString()
+            while (checkString.length > 0 && resultStr.length > 0) {
+                let subc = checkString.substring(to: 1) as NSString
+                let subr = resultStr.substring(to: 1) as NSString
+                
+                let cRange = checkString.range(of: subr as String)
+                let rRange = resultStr.range(of: subc as String)
+                
+                if subc.isEqual(to: subr) { // (A0 = B0)
+                                            // Check Success
+                    callback(attributeStringWith(skipString, failString: failString))
+//                    failure(skipString, failString)
+//                    self.appendErrorInfo(skipString, failString: failString)
+                    skipString = NSString()
+                    failString = NSString()
+                    
+                    
+                    checkString = checkString.substring(from:1) as NSString
+                    resultStr = resultStr.substring(from:1) as NSString
+                    successCount = successCount + 1
+                    callback(NSAttributedString(string: subc as String))
+                } else if (cRange.location != NSNotFound &&
+                           rRange.location != NSNotFound) {
+                    if (min(cRange.location, rRange.location) >= 2) {
+                        let nextc = checkString.substring(with: NSRange(location: 1, length: 1)) as NSString
+                        let nextr = resultStr.substring(with: NSRange(location: 1, length: 1)) as NSString
+                        let ncRange = checkString.range(of: nextr as String)
+                        let nrRange = resultStr.range(of: nextc as String)
+                        
+                        if (min(nrRange.location, ncRange.location) < min(cRange.location, rRange.location)) {
+                            if (ncRange.location < nrRange.location) {
+                                //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
+                                skipString = skipString.appending(subc as String) as NSString
+                                checkString = checkString.substring(from:1) as NSString
+                            }else {
+                                //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
+                                failString = failString.appending(subr as String) as NSString
+                                resultStr = resultStr.substring(from:1) as NSString
+                            }
+                        }else if (cRange.location < rRange.location) {
+                            //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
+                            skipString = skipString.appending(subc as String) as NSString
+                            checkString = checkString.substring(from:1) as NSString
+                        }else {
+                            //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
+                            failString = failString.appending(subr as String) as NSString
+                            resultStr = resultStr.substring(from:1) as NSString
+                        }
+                    }else {
+//                        var scale = (skipString.length > 0) ? (Float(checkString.length) / Float(skipString.length)) : Float(1.0)
+//                        if (checkString.length > skipString.length && cRange.location <= Int(Float(rRange.location)*scale)) {
+//                            //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
+//                            skipString = skipString.appending(subc as String) as NSString
+//                            checkString = checkString.substring(from:1) as NSString
+//                        }else if (checkString.length <= skipString.length && cRange.location > Int(Float(rRange.location)*scale)) {
+//                            failString = failString.appending(subr as String) as NSString
+//                            resultStr = resultStr.substring(from:1) as NSString
+//                        }else
+                        if (cRange.location < rRange.location) {
+                            //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
+                            skipString = skipString.appending(subc as String) as NSString
+                            checkString = checkString.substring(from:1) as NSString
+                        }else  {
+                            //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
+                            failString = failString.appending(subr as String) as NSString
+                            resultStr = resultStr.substring(from:1) as NSString
+                        }
+//                        //                    self.appendErrorInfo(skipString, failString: failString)
+//                        callback(attributeStringWith(skipString, failString: failString))
+//                        //                    failure(skipString, failString)
+//                        skipString = NSString()
+//                        failString = NSString()
+//
+//                        // C:a[bcde]fghij
+//                        // R:f[klmnbvcx]a
+//                        if (cRange.location < rRange.location) {
+//                            let cacheString = checkString.substring(to:cRange.location + cRange.length)
+//                            callback(attributeStringWith(cacheString as NSString, failString: ""))
+//                            //                        failure(cacheString as NSString, "")
+//                            //                        self.reportString?.append(NSMutableAttributedString.init(string: "对照字符串【\(cacheString)】未识别到\n",
+//                            //                                                                                 attributes:[.foregroundColor : NSColor.red]))
+//                            checkString = checkString.substring(from:cRange.location) as NSString
+//                        }else {
+//                            let cacheString = resultStr.substring(to:rRange.location)
+//                            callback(attributeStringWith("", failString: cacheString as NSString))
+//                            //                        failure("", cacheString as NSString)
+//                            //                        self.reportString?.append(NSMutableAttributedString.init(string: "字符串【\(cacheString)】识别出错\n",
+//                            //                                                                                 attributes:[.foregroundColor : NSColor.red]))
+//                            resultStr = resultStr.substring(from:rRange.location + rRange.length) as NSString
+//                        }
+                    }
+                }else if (cRange.location != NSNotFound) {
+                    //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
+                    skipString = skipString.appending(subc as String) as NSString
+                    checkString = checkString.substring(from:1) as NSString
+                }else if (rRange.location != NSNotFound) {
+                    //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
+                    failString = failString.appending(subr as String) as NSString
+                    resultStr = resultStr.substring(from:1) as NSString
+                }else {
+                    //  两个子字串均未找到
+                    skipString = skipString.appending(subc as String) as NSString
+                    failString = failString.appending(subr as String) as NSString
+                    
+                    checkString = checkString.substring(from:1) as NSString
+                    resultStr = resultStr.substring(from:1) as NSString
+                }
+            }
+            
+            skipString = skipString.appending(checkString as String) as NSString
+            failString = failString.appending(resultStr as String) as NSString
+//            failure(skipString, failString)
+            callback(attributeStringWith(skipString, failString: failString))
+            callback(NSAttributedString(string: "\n"))
+            
+            let degree = (maxSize>1) ? Double(Float(successCount)/Float(maxSize) * 100) : 0
+            
+            return degree
+        }
+    }
+    
+}

+ 0 - 516
KdanAutoTest/KdanAuto/Class/AutoTestCase/StringAutoCompare.swift

@@ -1,516 +0,0 @@
-//
-//  CharacterAutoTest.swift
-//  KdanAuto
-//
-//  Created by 朱东勇 on 2022/11/22.
-//
-
-import Foundation
-import Cocoa
-
-class StringAutoCompare : AutoTest {
-    
-//    override func type() -> String {
-//        return "PDFConvert_China_Auto_Test"
-//    }
-    
-    override func name() -> String {
-        return _name
-    }
-    
-    override func keys() -> NSArray {
-        return ["字符"]
-    }
-    
-    
-    override func needTest() -> Bool {
-        return self.selectedKeys().count > 0
-    }
-    
-    
-    override class func shared() -> AutoTest? {
-        return StringAutoCompare()
-    }
-    
-    
-    // Auto Test refrence Check File
-    override func autoTest(_ complention:@escaping (_ object:AutoTest, _ report:NSAttributedString?) -> ()) {
-        self.compareFinishedFiles.removeAllObjects();
-        self.convertFiles.removeAllObjects()
-        
-//        clearCacheFiles()
-        
-        let needCheckString = self.selectedKeys().contains("字符")
-        
-        if !needCheckString {
-            _status = .Finished
-            complention(self, self.reportString)
-            return
-        }
-        
-        _status = .Process
-        reportString = NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】字符比对开始!\n",
-                                                      attributes:[.foregroundColor : NSColor.blue])
-        let files = DataModel.shared.originFilesFor(_fileType, type: _type)
-        self.testFiles = NSArray(array: files);
-        
-        let checkDirectory = self.checkFileDirectory()
-        let originDirectory = self.originFileDirectory()
-        let resultDirectory = self.resultFileDirectory()
-        
-        if (files.count > 0) {
-            try? FileManager.default.createDirectory(atPath: checkDirectory, withIntermediateDirectories: true);
-            try? FileManager.default.createDirectory(atPath: resultDirectory, withIntermediateDirectories: true);
-        }
-        
-        var tDegree = Double(0);
-        var tCount = Int(0)
-        var fileIndex = 0;
-        
-        var convertFileBlock = { (files:[String]) in }
-        convertFileBlock = { (files:[String]) in
-            if (fileIndex >= files.count) {
-                TestDegreeManager.shared().set(((tCount != 0) ? tDegree/Double(tCount) : 0.0),
-                                               fileType: self.fileType(),
-                                               type: self.type())
-                
-                self._status = .Finished
-                DispatchQueue.main.async {
-                    autoreleasepool {
-                        complention(self, self.reportString);
-                    }
-                }
-                return
-            }
-            
-            let fileName = files[fileIndex]
-            let fName = NSString(string: fileName).deletingPathExtension
-            let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf")
-            let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+self.extention())
-            let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+self.extention())
-            
-            
-            self.reportString?.append(NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】开始转换文件 \"\(fName)\"\n",
-                                                                attributes:[.foregroundColor : NSColor.black]))
-            // ...
-            // 执行转换过程
-            let index = self.testFiles.index(of: fileName);
-            if (index != NSNotFound) {
-                self.convertProgress = Double(index) / Double(self.testFiles.count)
-            }
-            self.convertFiles.add(fileName);
-            self.testlog("开始对照:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
-//            self.process(originPath, resultPath: resultPath) { status in
-                let status = 1
-                if FileManager.default.fileExists(atPath: resultPath) && status == 1 {
-                    if needCheckString && FileManager.default.fileExists(atPath: checkPath) {
-                        DispatchQueue.global().async {
-                            let checkString = self.readTextFile(checkPath as NSString)
-                            let resultStr = self.readTextFile(resultPath as NSString)
-                            
-                            if (checkString != nil && resultStr != nil) {
-                                let maxSize = checkString!.count
-                                let report = NSMutableAttributedString(string: "")
-                                let degree = self.compareString(checkString as! NSString, result: resultStr as! NSString) { appAttr in
-                                    report.append(appAttr)
-                                }
-//                                let degree = self.compareString(checkString as! NSString, result: resultStr as! NSString) { skipString, failString in
-//                                    self.appendErrorInfo(skipString, failString: failString)
-//                                }
-                                
-                                var color = NSColor.black
-                                if fabs(degree-100.0) >= 0.01 {
-                                    color = NSColor.red
-                                }
-                                tDegree += degree;
-                                tCount += 1
-                                
-                                TestDegreeManager.shared().set(degree,
-                                                               fileType: self.fileType(),
-                                                               type: self.type(),
-                                                               fileName: fileName)
-                                
-                                let successCount = Int(maxSize * Int(degree)/100)
-                                report.append(NSAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"比对完成,准确率\(degree)%(\(successCount)/\(maxSize))\n",
-                                                                                  attributes:[.foregroundColor : color]))
-                                if (report != nil) {
-                                    do {
-                                        let rtfData = try? report.data(from: .init(location: 0, length: report.length),
-                                                                                   documentAttributes: [.documentType: NSAttributedString.DocumentType.rtf])
-                                        
-                                        let path = NSString(string: resultPath).appendingPathExtension("rtf")
-                                        try? FileManager.default.removeItem(atPath: path!);
-                                        try? rtfData?.write(to: NSURL.fileURL(withPath: path!))
-                                    } catch {
-                                    }
-                                    self.reportString?.append(report)
-                                }
-                            }
-                            
-                            let index = self.testFiles.index(of: fileName);
-                            if (index != NSNotFound) {
-                                self.compareProgress = Double(index) / Double(self.testFiles.count)
-                            }
-                            self.compareFinishedFiles.add(fileName);
-                            self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
-                            
-                            fileIndex += 1
-                            convertFileBlock(files);
-                        }
-                    }else {
-                        self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】对照文件 \"\(fName)\"不存在!\n",
-                                                                                 attributes:[.foregroundColor : NSColor.red]))
-                            
-                        let index = self.testFiles.index(of: fileName);
-                        if (index != NSNotFound) {
-                            self.compareProgress = Double(index) / Double(self.testFiles.count)
-                        }
-                        self.compareFinishedFiles.add(fileName);
-                        self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
-                        
-                        fileIndex += 1
-                        convertFileBlock(files);
-                    }
-                }else {
-                    if (status == 0) {
-                        self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档失败!\n",
-                                                                            attributes:[.foregroundColor : NSColor.red]))
-                    }else if (status == -1 || status == -2) {
-                        self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"文档无法打开!\n",
-                                                                            attributes:[.foregroundColor : NSColor.red]))
-                    }else if (status == -3) {
-                        self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档中 Crash!\n",
-                                                                            attributes:[.foregroundColor : NSColor.red]))
-                    }
-                    
-                    let index = self.testFiles.index(of: fileName);
-                    if (index != NSNotFound) {
-                        self.compareProgress = Double(index) / Double(self.testFiles.count)
-                    }
-                    self.compareFinishedFiles.add(fileName);
-                    self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
-                    fileIndex += 1
-                    convertFileBlock(files);
-                }
-//            }
-        }
-        convertFileBlock(files);
-    }
-    
-    ///Compare
-    
-    /// Tools
-    func appendErrorInfo(_ skipString:NSString, failString: NSString) {
-        if skipString.length > 0  && failString.length > 0 {
-            reportString?.append(NSMutableAttributedString.init(string: "对比字符串【\(skipString)】错识别为【\(failString)】\n",
-                                                                attributes:[.foregroundColor : NSColor.red]))
-        }else if (skipString.length > 0) {
-            reportString?.append(NSMutableAttributedString.init(string: "对比字符串【\(skipString)】未识别到\n",
-                                                                attributes:[.foregroundColor : NSColor.red]))
-        }else if failString.length > 0 {
-            reportString?.append(NSMutableAttributedString.init(string: "字符串【\(failString)】识别出错\n",
-                                                                attributes:[.foregroundColor : NSColor.red]))
-        }
-    }
-    
-    func attributeStringWith(_ skipString:NSString, failString: NSString) -> NSAttributedString {
-        if skipString.length > 0  && failString.length > 0 {
-            let strikethroughStyle = NSParagraphStyle.init()
-            let attString = NSMutableAttributedString.init(string: skipString as String,
-                                                           attributes:[.foregroundColor : NSColor.red,
-                                                                       .strikethroughStyle:NSNumber(integerLiteral: NSUnderlineStyle.single.rawValue),
-                                                                       ])
-            attString.append(NSMutableAttributedString.init(string: failString as String,
-                                                            attributes:[.foregroundColor : NSColor.blue,
-                                                            ]))
-            return attString
-        }else if (skipString.length > 0) {
-            let strikethroughStyle = NSParagraphStyle.init()
-            let attString = NSMutableAttributedString.init(string: skipString as String,
-                                                           attributes:[.foregroundColor : NSColor.red,
-                                                                       .strikethroughStyle:NSNumber(integerLiteral: NSUnderlineStyle.single.rawValue),
-                                                           ])
-            return attString
-        }else if failString.length > 0 {
-            let strikethroughStyle = NSParagraphStyle.init()
-            let attString = NSMutableAttributedString.init(string: failString as String,
-                                                           attributes:[.foregroundColor : NSColor.blue,
-                                                                      ])
-            return attString
-        }
-        
-        return NSAttributedString()
-    }
-    
-    func replaceUnicodeString(_ string:NSString) -> NSString {//中
-        let items = string.components(separatedBy: "\\u") as [NSString]
-        
-        var resultString = NSString()
-        for item in items {
-            if (item.contains("?")) {
-                let unicodeValue = item.intValue
-                let skipRange = item.range(of: "?")
-                let nextString = item.substring(from: Int(skipRange.location + skipRange.length)) as NSString
-                let bytes : [UInt8] = [UInt8(unicodeValue/256),UInt8(unicodeValue%256)]
-                let data = NSData.init(bytes: bytes, length: 2)
-                
-                let unicodeString = NSString.init(data: data as Data, encoding: NSUnicodeStringEncoding)! as NSString
-                resultString = resultString.appending(String("\(unicodeString)\(nextString)")) as NSString
-            }else {
-                resultString = resultString.appending(String(item)) as NSString
-            }
-        }
-        
-        return resultString
-    }
-    
-    
-    /// Compare
-    func compareString(_ check:NSString, result:NSString, callback:@escaping (_ appAttr:NSAttributedString)->()) -> Double {
-//    func compareString(_ check:NSString, result:NSString, failure:@escaping (_ skipString:NSString, _ failString:NSString)->()) -> Double {
-        return autoreleasepool {
-            var checkString = check
-            var resultStr = result
-            let maxSize = checkString.length
-            var successCount = 0;
-            /**
-             (A0 = B0)
-             - A-1 & B-1
-             (A0 != B0) & (A0 in B) & (B0 in A)
-             - 取 A0,B0最小 Range 值
-             - 字符串裁剪对齐
-             (A0 != B0) & (A0 in B)
-             - 存储B0到识别错误缓存
-             (A0 != B0) & (B0 in A)
-             - 存储 A0到识别遗漏字符串
-             (A0 != B0)
-             - 分别存储 A0、B0到遗漏及错误字串
-             */
-            var skipString = NSString()
-            var failString = NSString()
-            while (checkString.length > 0 && resultStr.length > 0) {
-                let subc = checkString.substring(to: 1) as NSString
-                let subr = resultStr.substring(to: 1) as NSString
-                
-                let cRange = checkString.range(of: subr as String)
-                let rRange = resultStr.range(of: subc as String)
-                
-                if subc.isEqual(to: subr) { // (A0 = B0)
-                                            // Check Success
-                    callback(attributeStringWith(skipString, failString: failString))
-//                    failure(skipString, failString)
-//                    self.appendErrorInfo(skipString, failString: failString)
-                    skipString = NSString()
-                    failString = NSString()
-                    
-                    
-                    checkString = checkString.substring(from:1) as NSString
-                    resultStr = resultStr.substring(from:1) as NSString
-                    successCount = successCount + 1
-                    callback(NSAttributedString(string: subc as String))
-                } else if (cRange.location != NSNotFound &&
-                           rRange.location != NSNotFound) {
-                    if (min(cRange.location, rRange.location) >= 2) {
-                        let nextc = checkString.substring(with: NSRange(location: 1, length: 1)) as NSString
-                        let nextr = resultStr.substring(with: NSRange(location: 1, length: 1)) as NSString
-                        let ncRange = checkString.range(of: nextr as String)
-                        let nrRange = resultStr.range(of: nextc as String)
-                        
-                        if (min(nrRange.location, ncRange.location) < min(cRange.location, rRange.location)) {
-                            if (ncRange.location < nrRange.location) {
-                                //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
-                                skipString = skipString.appending(subc as String) as NSString
-                                checkString = checkString.substring(from:1) as NSString
-                            }else {
-                                //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
-                                failString = failString.appending(subr as String) as NSString
-                                resultStr = resultStr.substring(from:1) as NSString
-                            }
-                        }else if (cRange.location < rRange.location) {
-                            //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
-                            skipString = skipString.appending(subc as String) as NSString
-                            checkString = checkString.substring(from:1) as NSString
-                        }else {
-                            //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
-                            failString = failString.appending(subr as String) as NSString
-                            resultStr = resultStr.substring(from:1) as NSString
-                        }
-                    }else {
-                        if (cRange.location < rRange.location) {
-                            //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
-                            skipString = skipString.appending(subc as String) as NSString
-                            checkString = checkString.substring(from:1) as NSString
-                        }else {
-                            //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
-                            failString = failString.appending(subr as String) as NSString
-                            resultStr = resultStr.substring(from:1) as NSString
-                        }
-//                        //                    self.appendErrorInfo(skipString, failString: failString)
-//                        callback(attributeStringWith(skipString, failString: failString))
-//                        //                    failure(skipString, failString)
-//                        skipString = NSString()
-//                        failString = NSString()
-//
-//                        // C:a[bcde]fghij
-//                        // R:f[klmnbvcx]a
-//                        if (cRange.location < rRange.location) {
-//                            let cacheString = checkString.substring(to:cRange.location + cRange.length)
-//                            callback(attributeStringWith(cacheString as NSString, failString: ""))
-//                            //                        failure(cacheString as NSString, "")
-//                            //                        self.reportString?.append(NSMutableAttributedString.init(string: "对照字符串【\(cacheString)】未识别到\n",
-//                            //                                                                                 attributes:[.foregroundColor : NSColor.red]))
-//                            checkString = checkString.substring(from:cRange.location) as NSString
-//                        }else {
-//                            let cacheString = resultStr.substring(to:rRange.location)
-//                            callback(attributeStringWith("", failString: cacheString as NSString))
-//                            //                        failure("", cacheString as NSString)
-//                            //                        self.reportString?.append(NSMutableAttributedString.init(string: "字符串【\(cacheString)】识别出错\n",
-//                            //                                                                                 attributes:[.foregroundColor : NSColor.red]))
-//                            resultStr = resultStr.substring(from:rRange.location + rRange.length) as NSString
-//                        }
-                    }
-                }else if (cRange.location != NSNotFound) {
-                    //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
-                    skipString = skipString.appending(subc as String) as NSString
-                    checkString = checkString.substring(from:1) as NSString
-                }else if (rRange.location != NSNotFound) {
-                    //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
-                    failString = failString.appending(subr as String) as NSString
-                    resultStr = resultStr.substring(from:1) as NSString
-                }else {
-                    //  两个子字串均未找到
-                    skipString = skipString.appending(subc as String) as NSString
-                    failString = failString.appending(subr as String) as NSString
-                    
-                    checkString = checkString.substring(from:1) as NSString
-                    resultStr = resultStr.substring(from:1) as NSString
-                }
-            }
-            
-            skipString = skipString.appending(checkString as String) as NSString
-            failString = failString.appending(resultStr as String) as NSString
-//            failure(skipString, failString)
-            callback(attributeStringWith(skipString, failString: failString))
-            callback(NSAttributedString(string: "\n"))
-            
-            let degree = (maxSize>1) ? Double(Float(successCount)/Float(maxSize) * 100) : 0
-            
-            return degree
-        }
-    }
-    
-    // Read File
-    func readTextFile(_ filePath:NSString) -> String? {
-        if NSArray(array: ["TXT", "txt"]).contains(filePath.pathExtension) {
-            var checkString = try? NSString.init(contentsOfFile: filePath as String, encoding: NSUTF8StringEncoding)
-            if (checkString != nil) {
-                checkString = checkString!.replacingOccurrences(of: "\n", with: "") as NSString
-                checkString = checkString!.replacingOccurrences(of: " ", with: "") as NSString
-                return checkString! as String
-            }
-            return nil
-        }else if NSArray(array: ["rtf", "RTF"]).contains(filePath.pathExtension) {
-            // Load check file
-            let checkData = NSData.init(contentsOfFile: filePath as String) as! Data
-            var documentAttributes:NSDictionary!
-            let checkAttString = NSAttributedString.init(rtf: checkData, documentAttributes: &documentAttributes)
-            var checkString = NSString(string: checkAttString!.string) as NSString
-            checkString = checkString.replacingOccurrences(of: "\n", with: "") as NSString
-            checkString = checkString.replacingOccurrences(of: " ", with: "") as NSString
-            // 常规 rtf 读取失败
-            
-            //使用框排进行读取
-            if (checkString.length > 0) {
-                return checkString as String?
-            }
-            
-            var resultString = try? NSString.init(contentsOfFile: filePath as String, encoding: NSUTF8StringEncoding)
-            
-            if (nil != resultString && !resultString!.contains("\\shptxt\\shptxt")) {
-                resultString = resultString!.replacingOccurrences(of: "\n", with: "") as NSString
-                resultString = resultString!.replacingOccurrences(of: " ", with: "") as NSString
-                return resultString! as String
-            }
-            
-            //识别字符串 \shptxt\shptxt ... }
-            let pageInfoStrings = resultString!.components(separatedBy: "\\shptxt\\shptxt") as NSArray
-            var finalString = ""
-            if pageInfoStrings.count > 0 {
-                let subStrings = pageInfoStrings.subarray(with: NSMakeRange(1, Int(pageInfoStrings.count - 1))) as! [String]
-                for pageInfoString in subStrings {
-                    let endRange = NSString(string: pageInfoString).range(of: "}")
-                    finalString = finalString.appending(NSString(string: pageInfoString).substring(to: endRange.location))
-                }
-            }
-            
-            
-            //识别所有 【空格 ~ \】 之间的值,并进行缝合
-            // Detect all strings between Spaces and \ and stitch
-            let strings = finalString.components(separatedBy: " ")
-            var resultStr = "" as NSString
-            for str in strings {
-                let markStr = str as NSString
-                
-                if (markStr.contains("\\f")) {
-                    let fRange = markStr.range(of: "\\f")
-                    let cRange = markStr.range(of: "\\c")
-                    let bRange = markStr.range(of: "\\b")
-                    let iRange = markStr.range(of: "\\i")
-                    let eRange = markStr.range(of: "\\e")
-                    let pRange = markStr.range(of: "\\p")
-                    let minPos = min(Int(fRange.location),
-                                     Int(cRange.location),
-                                     Int(bRange.location),
-                                     Int(iRange.location),
-                                     Int(eRange.location),
-                                     Int(pRange.location))
-                    resultStr = resultStr.appending(markStr.substring(to: minPos)) as NSString
-                }else {
-                    resultStr = resultStr.appending(markStr as String) as NSString
-                }
-            }
-            
-            resultStr = self.replaceUnicodeString(resultStr)
-            
-            
-            resultStr = resultStr.replacingOccurrences(of: "\n", with: "") as NSString
-            resultStr = resultStr.replacingOccurrences(of: " ", with: "") as NSString
-            resultStr = resultStr.replacingOccurrences(of: "\\pard", with: "") as NSString
-            resultStr = resultStr.replacingOccurrences(of: "\\par", with: "") as NSString
-            
-            return resultStr as String?
-        }
-        
-        return nil
-    }
-    
-    
-    override func compareFiles() -> NSArray? {
-        return nil
-    }
-    
-    override func compareFiles(_ fileName: String) -> NSArray? {
-        return nil
-    }
-    
-    
-    /**
-     Replace the refrence image for next image check test
-     */
-    override func canUpdateRefImage() -> Bool {
-        return false
-    }
-    
-    override func updateRefImage() {
-        
-    }
-    
-    override func canUpdateRefImage(_ fileName:String) -> Bool {
-        return false
-    }
-    
-    override func updateRefImage(_ fileName:String) {
-        
-    }
-    
-}

+ 192 - 0
KdanAutoTest/KdanAuto/Class/AutoTestCase/StringAutoCompareTest.swift

@@ -0,0 +1,192 @@
+//
+//  CharacterAutoTest.swift
+//  KdanAuto
+//
+//  Created by 朱东勇 on 2022/11/22.
+//
+
+import Foundation
+import Cocoa
+
+class StringAutoCompareTest : StringAutoTest {
+    
+    override class func shared() -> AutoTest? {
+        return StringAutoCompareTest()
+    }
+    
+    
+    // Auto Test refrence Check File
+    override func autoTest(_ complention:@escaping (_ object:AutoTest, _ report:NSAttributedString?) -> ()) {
+        self.compareFinishedFiles.removeAllObjects();
+        self.convertFiles.removeAllObjects()
+        
+//        clearCacheFiles()
+        
+        let needCheckString = self.selectedKeys().contains("字符")
+        
+        if !needCheckString {
+            _status = .Finished
+            complention(self, self.reportString)
+            return
+        }
+        
+        _status = .Process
+        reportString = NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】字符比对开始!\n",
+                                                      attributes:[.foregroundColor : NSColor.blue])
+        let files = DataModel.shared.originFilesFor(_fileType, type: _type)
+        self.testFiles = NSArray(array: files);
+        
+        let checkDirectory = self.checkFileDirectory()
+        let originDirectory = self.originFileDirectory()
+        let resultDirectory = self.resultFileDirectory()
+        
+        if (files.count > 0) {
+            try? FileManager.default.createDirectory(atPath: checkDirectory, withIntermediateDirectories: true);
+            try? FileManager.default.createDirectory(atPath: resultDirectory, withIntermediateDirectories: true);
+        }
+        
+        var tDegree = Double(0);
+        var tCount = Int(0)
+        var fileIndex = 0;
+        
+        var convertFileBlock = { (files:[String]) in }
+        convertFileBlock = { (files:[String]) in
+            if (fileIndex >= files.count) {
+                TestDegreeManager.shared().set(((tCount != 0) ? tDegree/Double(tCount) : 0.0),
+                                               fileType: self.fileType(),
+                                               type: self.type())
+                
+                self._status = .Finished
+                DispatchQueue.main.async {
+                    autoreleasepool {
+                        complention(self, self.reportString);
+                    }
+                }
+                return
+            }
+            
+            let fileName = files[fileIndex]
+            let fName = NSString(string: fileName).deletingPathExtension
+            let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf")
+            let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+self.extention())
+            let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+self.extention())
+            
+            
+            self.reportString?.append(NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】开始转换文件 \"\(fName)\"\n",
+                                                                attributes:[.foregroundColor : NSColor.black]))
+            // ...
+            // 执行转换过程
+            let index = self.testFiles.index(of: fileName);
+            if (index != NSNotFound) {
+                self.convertProgress = Double(index) / Double(self.testFiles.count)
+            }
+            self.convertFiles.add(fileName);
+            self.testlog("开始对照:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
+//            self.process(originPath, resultPath: resultPath) { status in
+                let status = 1
+                if FileManager.default.fileExists(atPath: resultPath) && status == 1 {
+                    if needCheckString && FileManager.default.fileExists(atPath: checkPath) {
+                        DispatchQueue.global().async {
+                            let checkString = self.readTextFile(checkPath as NSString)
+                            let resultStr = self.readTextFile(resultPath as NSString)
+                            
+                            if (checkString != nil && resultStr != nil) {
+                                let maxSize = checkString!.count
+                                let report = NSMutableAttributedString(string: "")
+                                let degree = self.compareString(checkString as! NSString, result: resultStr as! NSString) { appAttr in
+                                    report.append(appAttr)
+                                }
+//                                let degree = self.compareString(checkString as! NSString, result: resultStr as! NSString) { skipString, failString in
+//                                    self.appendErrorInfo(skipString, failString: failString)
+//                                }
+                                
+                                var color = NSColor.black
+                                if fabs(degree-100.0) >= 0.01 {
+                                    color = NSColor.red
+                                }
+                                tDegree += degree;
+                                tCount += 1
+                                
+                                TestDegreeManager.shared().set(degree,
+                                                               fileType: self.fileType(),
+                                                               type: self.type(),
+                                                               fileName: fileName)
+                                
+                                let successCount = Int(maxSize * Int(degree)/100)
+                                report.append(NSAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"比对完成,准确率\(degree)%(\(successCount)/\(maxSize))\n",
+                                                                                  attributes:[.foregroundColor : color]))
+                                if (report != nil) {
+                                    do {
+                                        let rtfData = try? report.data(from: .init(location: 0, length: report.length),
+                                                                                   documentAttributes: [.documentType: NSAttributedString.DocumentType.rtf])
+                                        
+                                        let path = NSString(string: resultPath).appendingPathExtension("rtf")
+                                        try? FileManager.default.removeItem(atPath: path!);
+                                        try? rtfData?.write(to: NSURL.fileURL(withPath: path!))
+                                    } catch {
+                                    }
+                                    self.reportString?.append(report)
+                                }
+                            }
+                            
+                            let index = self.testFiles.index(of: fileName);
+                            if (index != NSNotFound) {
+                                self.compareProgress = Double(index) / Double(self.testFiles.count)
+                            }
+                            self.compareFinishedFiles.add(fileName);
+                            self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
+                            
+                            fileIndex += 1
+                            convertFileBlock(files);
+                        }
+                    }else {
+                        self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】对照文件 \"\(fName)\"不存在!\n",
+                                                                                 attributes:[.foregroundColor : NSColor.red]))
+                            
+                        let index = self.testFiles.index(of: fileName);
+                        if (index != NSNotFound) {
+                            self.compareProgress = Double(index) / Double(self.testFiles.count)
+                        }
+                        self.compareFinishedFiles.add(fileName);
+                        self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
+                        
+                        fileIndex += 1
+                        convertFileBlock(files);
+                    }
+                }else {
+                    if (status == 0) {
+                        self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档失败!\n",
+                                                                            attributes:[.foregroundColor : NSColor.red]))
+                    }else if (status == -1 || status == -2) {
+                        self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"文档无法打开!\n",
+                                                                            attributes:[.foregroundColor : NSColor.red]))
+                    }else if (status == -3) {
+                        self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档中 Crash!\n",
+                                                                            attributes:[.foregroundColor : NSColor.red]))
+                    }
+                    
+                    let index = self.testFiles.index(of: fileName);
+                    if (index != NSNotFound) {
+                        self.compareProgress = Double(index) / Double(self.testFiles.count)
+                    }
+                    self.compareFinishedFiles.add(fileName);
+                    self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
+                    fileIndex += 1
+                    convertFileBlock(files);
+                }
+//            }
+        }
+        convertFileBlock(files);
+    }
+    
+}
+
+
+// Dispared
+class StringAutoCompare : StringAutoCompareTest {
+    
+    override class func shared() -> AutoTest? {
+        return StringAutoCompareTest()
+    }
+    
+}

+ 12 - 3
KdanAutoTest/KdanAuto/Class/AutoTestCase/StringAutoTest.swift

@@ -335,11 +335,20 @@ class StringAutoTest : AutoTest {
                             resultStr = resultStr.substring(from:1) as NSString
                         }
                     }else {
+//                        var scale = (skipString.length > 0) ? (Float(checkString.length) / Float(skipString.length)) : Float(1.0)
+//                        if (checkString.length > skipString.length && cRange.location <= Int(Float(rRange.location)*scale)) {
+//                            //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
+//                            skipString = skipString.appending(subc as String) as NSString
+//                            checkString = checkString.substring(from:1) as NSString
+//                        }else if (checkString.length <= skipString.length && cRange.location > Int(Float(rRange.location)*scale)) {
+//                            failString = failString.appending(subr as String) as NSString
+//                            resultStr = resultStr.substring(from:1) as NSString
+//                        }else
                         if (cRange.location < rRange.location) {
                             //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
                             skipString = skipString.appending(subc as String) as NSString
                             checkString = checkString.substring(from:1) as NSString
-                        }else {
+                        }else  {
                             //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
                             failString = failString.appending(subr as String) as NSString
                             resultStr = resultStr.substring(from:1) as NSString
@@ -403,8 +412,8 @@ class StringAutoTest : AutoTest {
         if NSArray(array: ["TXT", "txt"]).contains(filePath.pathExtension) {
             var checkString = try? NSString.init(contentsOfFile: filePath as String, encoding: NSUTF8StringEncoding)
             if (checkString != nil) {
-                checkString = checkString!.replacingOccurrences(of: "\n", with: "") as NSString
-                checkString = checkString!.replacingOccurrences(of: " ", with: "") as NSString
+//                checkString = checkString!.replacingOccurrences(of: "\n", with: "") as NSString
+//                checkString = checkString!.replacingOccurrences(of: " ", with: "") as NSString
                 return checkString! as String
             }
             return nil

BIN
PropertySettingGuide.pdf


BIN
PropertySettingGuide/KdanAuto 参数规则控制流程.png


BIN
PropertySettingGuide/OCR.language.params.png


+ 318 - 0
PropertySettingGuide/PropertySettingGuide.md

@@ -0,0 +1,318 @@
+#转档参数设置帮助
+
+##一、背景
+‘KdanAuto’作为用于(半)自动化转档测试工具,用于降低重复的、需要占用大量QA 人力的工作量的工具,其App 自身的开发时间投入,也是需要纳入重点考虑。
+     
+基于未来转档、DocumentAI SDK 将会长期投入开发,相关控制参数定会持续增加, 用于同步测试的 KdanAuto 必然需要能够同步支持所新增的参数;同时 QA 用于测试的用例也必然会是随着需求增加而不断增长,相应测试项需要有更灵活的设置方式。
+
+因此,设计了该套 【SDK新增参数 -》更新控制规则 -》App 启动加载自动配置】 控制规则,如下图:
+
+![KdanAuto 参数规则控制流程](KdanAuto 参数规则控制流程.png)
+图 1.1.1 KdanAuto 参数规则控制流程
+
+##二、参数控制规则文档效果及样式
+注:该文档以转档 SDK1.7.0版本参数参考拟定
+
+###1、JPEG/PNG 格式
+- SDK  JPEG 格式参数信息
+![](jpeg.params.png)
+<center>图 2.1.1 SDK JPEG 格式参数信息<center/>
+
+- 参数控制 UI 效果
+ ![](jpeg.png)
+<center>图 2.1.2 参数控制 UI 效果<center/>
+
+- 参数规则属性配置
+![](jpeg.property.png)
+<center>图 2.1.3 参数规则属性配置<center/>
+
+- 参数规则配置详情
+
+		<key>JPEG</key>
+		<dict>
+			<key>Classs</key>
+			<array>
+				<dict>
+					<key>Name</key>
+					<string>快照对照测试</string>
+					<key>Class</key>
+					<string>AutoTest</string>
+				</dict>
+			</array>
+			<key>Extention</key>
+			<string>jpg</string>
+			<key>Params</key>
+			<array>
+				<dict>
+					<key>ValueType</key>
+					<string>int</string>
+					<key>Property</key>
+					<string>imageDpi</string>
+					<key>Name</key>
+					<string>Image DPI</string>
+					<key>DefaultValue</key>
+					<integer>216</integer>
+				</dict>
+				<dict>
+					<key>ValueType</key>
+					<string>BOOL</string>
+					<key>Property</key>
+					<string>isContainAnnotations</string>
+					<key>Name</key>
+					<string>Contain Annotations</string>
+					<key>DefaultValue</key>
+					<false/>
+				</dict>
+			</array>
+		</dict>
+
+###2、CSV 格式
+- SDK CSV 格式参数信息
+![](csv.params.png)
+<center>图 2.2.1 SDK CSV 格式参数信息<center/>
+
+- 参数控制 UI 效果
+ ![](csv.png)
+<center>图 2.2.2 参数控制 UI 效果<center/>
+
+- 参数规则属性配置
+![](csv.property.png)
+<center>图 2.2.3 参数规则属性配置<center/>
+
+- 参数规则配置详情
+
+
+		<key>CSV</key>
+		<dict>
+			<key>Classs</key>
+			<array>
+				<dict>
+					<key>Name</key>
+					<string>快照对照测试</string>
+					<key>Class</key>
+					<string>AutoTest</string>
+				</dict>
+			</array>
+			<key>Extention</key>
+			<string>csv</string>
+			<key>Params</key>
+			<array>
+				<dict>
+					<key>ValueType</key>
+					<string>BOOL</string>
+					<key>Property</key>
+					<string>isMergeCSV</string>
+					<key>Name</key>
+					<string>Merge CSV</string>
+					<key>DefaultValue</key>
+					<false/>
+				</dict>
+			</array>
+		</dict>
+
+###3、TXT 格式
+- SDK TXT 格式参数信息
+![](txt.params.png)
+<center>图 2.3.1 SDK TXT 格式参数信息<center/>
+
+- 参数控制 UI 效果
+ ![](txt.png)
+<center>图 2.3.2 参数控制 UI 效果<center/>
+
+- 参数规则属性配置
+![](txt.property.png)
+<center>图 2.3.3 参数规则属性配置<center/>
+
+
+###4、HTML 格式
+- SDK HTML 格式参数信息
+![](html.params.png)
+<center>图 2.4.1 SDK HTML 格式参数信息<center/>
+
+- 参数控制 UI 效果
+ ![](html.png)
+<center>图 2.4.2 参数控制 UI 效果<center/>
+
+- 参数规则属性配置
+![](html.property.png)
+<center>图 2.4.3 参数规则属性配置<center/>
+
+
+###5、Excel 格式
+- SDK Excel 格式参数信息
+![](excel.params.png)
+<center>图 2.5.1 SDK Excel 格式参数信息<center/>
+
+- 参数控制 UI 效果
+ ![](excel.png)
+<center>图 2.5.2 参数控制 UI 效果<center/>
+
+- 参数规则属性配置
+![](excel.property.png)
+<center>图 2.5.3 参数规则属性配置<center/>
+
+
+###6、PPT 格式
+- SDK PPT格式参数信息
+![](ppt.params.png)
+<center>图 2.6.1 SDK PPT 格式参数信息<center/>
+
+- 参数控制 UI 效果
+ ![](ppt.png)
+<center>图 2.6.2 参数控制 UI 效果<center/>
+
+- 参数规则属性配置
+![](ppt.property.png)
+<center>图 2.6.3 参数规则属性配置<center/>
+
+
+###7、Word 格式
+- SDK Word格式参数信息
+![](word.params.png)
+<center>图 2.7.1 SDK Word 格式参数信息<center/>
+
+- 参数控制 UI 效果
+ ![](word.png)
+<center>图 2.7.2 参数控制 UI 效果<center/>
+
+- 参数规则属性配置
+![](word.property.png)
+<center>图 2.7.3 参数规则属性配置<center/>
+
+
+###8、RTF 格式
+- SDK RTF格式参数信息
+![](rtf.params.png)
+<center>图 2.8.1 SDK RTF 格式参数信息<center/>
+
+- 参数控制 UI 效果
+ ![](rtf.png)
+<center>图 2.8.2 参数控制 UI 效果<center/>
+
+- 参数规则属性配置
+![](rtf.property.png)
+<center>图 2.8.3 参数规则属性配置<center/>
+
+###9、PDF 格式
+注:PDF -> PDF : PDF 文档对照测试,实际内部用到的转档为 PDF 转 JPEG格式,然后进行的 JPEG 图片对照
+
+- SDK JPEG格式参数信息
+<center>![](jpeg.params.png)<center/>
+<center>图 2.9.1 SDK JPEG 格式参数信息<center/>
+
+- 参数控制 UI 效果
+ ![](pdf.png)
+<center>图 2.9.2 参数控制 UI 效果<center/>
+
+- 参数规则属性配置
+![](pdf.property.png)
+<center>图 2.9.3 参数规则属性配置<center/>
+
+
+##三、参数设置规则
+### Classs - 测试类型设置
+作用于具体文档的具体测试类型,目前有支持的测试类型有:AutoTest(全类型文档,自动转档及快照对照测试)、PDFCompareTest(PDF 文档,逐页快照对比测试)、StringAutoTest(TXT/RTF 文档,自动转档及字符对比测试)、StringAutoCompare(TXT/RTF 文档,字符对比测试)
+
+#### Class 类型
+#####-【AutoTest】
+	
+- 用途:用于自动化转档到各种类型文档,再进行快照(JPEG 格式),然后将(新旧)快照(JPEG 格式)进行逐个相素对比
+
+- 支持格式:支持全类型格式,PDF、RTF、WORD、PPT、Excel、CSV、HTML、TXT、JPEG、PNG、GIF、TIFF、TGA、BMP、JPEG2000
+
+#####- 【PDFCompareTest】
+
+- 用途:用于对 PDF 文档,进行逐页快照对比测试;例如,在 Windows 端用命令行工具批量执行出来的结果文档,用该工具进行对照确认
+
+- 支持格式:PDF
+
+#####- 【StringAutoTest】
+
+- 用途:用于自动化转档到字符化文档(如 TXT、RTF),再将结果文档与初始字符文档进行字符对照测试
+
+- 支持格式:RTF、TXT
+
+
+#####- 【StringAutoCompare】
+
+- 用途:用于自动化对比字符化文档(如 TXT、RTF)的结果文档和对照文档,例如在 Windows 端做 OCR 识别,然后在 Mac 端进行结果对比
+
+- 支持格式:RTF、TXT
+
+
+####Class 参数设置
+
+#####- 示例一
+
+		//例如 Word 文档进行设置,支持做 【快照对照】
+		
+		<key>Classs</key>
+		<array>
+			<dict>
+				<key>Name</key>
+				<string>快照对照测试</string>
+				<key>Class</key>
+				<string>AutoTest</string>
+			</dict>
+		</array>
+
+![](word.class.png)
+图 3.1.1 Word 格式 Classs 参数设置效果示意图 
+
+#####- 示例二
+	
+	
+		//RTF 文档支持【转档快照对照】、【转档对比测试】、【字符对比操作】
+		<key>Classs</key>
+		<array>
+			<dict>
+				<key>Name</key>
+				<string>快照对照测试</string>
+				<key>Class</key>
+				<string>AutoTest</string>
+			</dict>
+			<dict>
+				<key>Name</key>
+				<string>字符对照测试</string>
+				<key>Class</key>
+				<string>StringAutoTest</string>
+			</dict>
+			<dict>
+				<key>Name</key>
+				<string>跨平台字符对比测试</string>
+				<key>Class</key>
+				<string>StringAutoCompare</string>
+			</dict>
+		</array>
+
+
+![](rtf.class.png)
+图 3.1.2 RTF 格式 Classs 参数设置效果示意图 
+
+### Extention - 结果文档格式后缀设置
+对应文档类型(转档后)对照(/对比)测试的文档后缀名称,每种格式对应指定一种后缀格式名称,字符串属性值
+
+- PDF:对应后缀 pdf
+-  RTF:对应后缀 rtf
+-  Word: 对应后缀 docx
+-  PPT: 对应后缀 pptx
+-  Excel:对应后缀 xlsx
+-  CSV: 对应后缀 csv
+-  HTML: 对应后缀 html
+-  TXT:对应后缀 txt
+-  JPEG:对应后缀 jpg
+-  PNG:对应后缀 png
+-  GIF:对应后缀 gif,新库暂不支持
+-  TIFF:对应后缀 tiff,新库暂不支持
+-  TGA:对应后缀 tga,新库暂不支持
+-  BMP:对应后缀 bmp,新库暂不支持
+-  JPEG2000:对应后缀jp2, 新库暂不支持
+
+![](all.extention.png)
+图 3.2.1 Extention参数设置示意
+
+### Params - 转档控制参数设置
+用于控制转档成各种文档过程中的转档控制参数,支持参数种类有 *BOOL*、*Bool*、*bool*、*size_t*、*int*、*uint8_t*、*int8_t*、*int16_t*、*uint16_t*、*int32_t*、*uint32_t*、*int64_t*、*uint64_t*、*NSInteger*、*NSUInteger*、*float*、*double*、*CGRect*、*NSRect*、*CGSize*、*NSSize*、*NSString*以及*枚举值*
+
+####1、各
+

BIN
PropertySettingGuide/all.extention.png


BIN
PropertySettingGuide/csv.params.png


BIN
PropertySettingGuide/csv.png


BIN
PropertySettingGuide/csv.property.png


BIN
PropertySettingGuide/excel.params.png


BIN
PropertySettingGuide/excel.png


BIN
PropertySettingGuide/excel.property.png


BIN
PropertySettingGuide/html.params.png


BIN
PropertySettingGuide/html.png


BIN
PropertySettingGuide/html.property.png


BIN
PropertySettingGuide/jpeg.params.png


BIN
PropertySettingGuide/jpeg.png


BIN
PropertySettingGuide/jpeg.property.png


BIN
PropertySettingGuide/pdf.png


BIN
PropertySettingGuide/pdf.property.png


BIN
PropertySettingGuide/png.png


BIN
PropertySettingGuide/png.property.png


BIN
PropertySettingGuide/ppt.params.png


BIN
PropertySettingGuide/ppt.png


BIN
PropertySettingGuide/ppt.property.png


BIN
PropertySettingGuide/rtf.class.png


BIN
PropertySettingGuide/rtf.params.png


BIN
PropertySettingGuide/rtf.png


BIN
PropertySettingGuide/rtf.property.png


BIN
PropertySettingGuide/txt.params.png


BIN
PropertySettingGuide/txt.png


BIN
PropertySettingGuide/txt.property.png


BIN
PropertySettingGuide/word.class.png


BIN
PropertySettingGuide/word.params.png


BIN
PropertySettingGuide/word.png


BIN
PropertySettingGuide/word.property.png


BIN
Use Guide.zip