StringAutoTest.swift 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. //
  2. // CharacterAutoTest.swift
  3. // KdanAuto
  4. //
  5. // Created by 朱东勇 on 2022/11/22.
  6. //
  7. import Foundation
  8. import Cocoa
  9. class StringAutoTest : AutoTest {
  10. // override func type() -> String {
  11. // return "PDFConvert_China_Auto_Test"
  12. // }
  13. override func name() -> String {
  14. return _name
  15. }
  16. override func keys() -> NSArray {
  17. return ["字符"]
  18. }
  19. override func needTest() -> Bool {
  20. return self.selectedKeys().count > 0
  21. }
  22. override class func shared() -> AutoTest? {
  23. return StringAutoTest()
  24. }
  25. // Auto Test refrence Check File
  26. override func autoTest(_ complention:@escaping (_ object:AutoTest, _ report:NSAttributedString?) -> ()) {
  27. self.compareFinishedFiles.removeAllObjects();
  28. self.convertFiles.removeAllObjects()
  29. clearCacheFiles()
  30. let needCheckString = self.selectedKeys().contains("字符")
  31. if !needCheckString {
  32. _status = .Finished
  33. complention(self, self.reportString)
  34. return
  35. }
  36. _status = .Process
  37. reportString = NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】字符比对开始!\n",
  38. attributes:[.foregroundColor : NSColor.blue])
  39. let files = DataModel.shared.originFilesFor(_fileType, type: _type)
  40. self.testFiles = NSArray(array: files);
  41. let checkDirectory = self.checkFileDirectory()
  42. let originDirectory = self.originFileDirectory()
  43. let resultDirectory = self.resultFileDirectory()
  44. if (files.count > 0) {
  45. try? FileManager.default.createDirectory(atPath: checkDirectory, withIntermediateDirectories: true);
  46. try? FileManager.default.createDirectory(atPath: resultDirectory, withIntermediateDirectories: true);
  47. }
  48. var tDegree = Double(0);
  49. var tCount = Int(0)
  50. var fileIndex = 0;
  51. var convertFileBlock = { (files:[String]) in }
  52. convertFileBlock = { (files:[String]) in
  53. if (fileIndex >= files.count) {
  54. TestDegreeManager.shared().set(((tCount != 0) ? tDegree/Double(tCount) : 0.0),
  55. fileType: self.fileType(),
  56. type: self.type())
  57. self._status = .Finished
  58. DispatchQueue.main.async {
  59. autoreleasepool {
  60. complention(self, self.reportString);
  61. }
  62. }
  63. return
  64. }
  65. let fileName = files[fileIndex]
  66. let fName = NSString(string: fileName).deletingPathExtension
  67. let originPath = NSString(string: originDirectory).appendingPathComponent(fName+".pdf")
  68. let resultPath = NSString(string: resultDirectory).appendingPathComponent(fName+"."+self.extention())
  69. let checkPath = NSString(string: checkDirectory).appendingPathComponent(fName+"."+self.extention())
  70. self.reportString?.append(NSMutableAttributedString.init(string: "\n【\(String(self.fileType())) - \(self.name())】开始转换文件 \"\(fName)\"\n",
  71. attributes:[.foregroundColor : NSColor.black]))
  72. // ...
  73. // 执行转换过程
  74. let index = self.testFiles.index(of: fileName);
  75. if (index != NSNotFound) {
  76. self.convertProgress = Double(index) / Double(self.testFiles.count)
  77. }
  78. self.convertFiles.add(fileName);
  79. self.testlog("开始转换:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
  80. self.process(originPath, resultPath: resultPath) { status in
  81. if FileManager.default.fileExists(atPath: resultPath) && status == 1 {
  82. if needCheckString && FileManager.default.fileExists(atPath: checkPath) {
  83. DispatchQueue.global().async {
  84. let checkString = self.readTextFile(checkPath as NSString)
  85. let resultStr = self.readTextFile(resultPath as NSString)
  86. if (checkString != nil && resultStr != nil) {
  87. let maxSize = checkString!.count
  88. let report = NSMutableAttributedString(string: "")
  89. let degree = self.compareString(checkString as! NSString, result: resultStr as! NSString) { appAttr in
  90. report.append(appAttr)
  91. }
  92. // let degree = self.compareString(checkString as! NSString, result: resultStr as! NSString) { skipString, failString in
  93. // self.appendErrorInfo(skipString, failString: failString)
  94. // }
  95. var color = NSColor.black
  96. if fabs(degree-100.0) >= 0.01 {
  97. color = NSColor.red
  98. }
  99. tDegree += degree;
  100. tCount += 1
  101. TestDegreeManager.shared().set(degree,
  102. fileType: self.fileType(),
  103. type: self.type(),
  104. fileName: fileName)
  105. let successCount = Int(maxSize * Int(degree)/100)
  106. report.append(NSAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"比对完成,准确率\(degree)%(\(successCount)/\(maxSize))\n",
  107. attributes:[.foregroundColor : color]))
  108. if (report != nil) {
  109. do {
  110. let rtfData = try? report.data(from: .init(location: 0, length: report.length),
  111. documentAttributes: [.documentType: NSAttributedString.DocumentType.rtf])
  112. let path = NSString(string: resultPath).appendingPathExtension("rtf")
  113. try? FileManager.default.removeItem(atPath: path!);
  114. try? rtfData?.write(to: NSURL.fileURL(withPath: path!))
  115. } catch {
  116. }
  117. self.reportString?.append(report)
  118. }
  119. }
  120. let index = self.testFiles.index(of: fileName);
  121. if (index != NSNotFound) {
  122. self.compareProgress = Double(index) / Double(self.testFiles.count)
  123. }
  124. self.compareFinishedFiles.add(fileName);
  125. self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
  126. fileIndex += 1
  127. convertFileBlock(files);
  128. }
  129. }else {
  130. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】对照文件 \"\(fName)\"不存在!\n",
  131. attributes:[.foregroundColor : NSColor.red]))
  132. let index = self.testFiles.index(of: fileName);
  133. if (index != NSNotFound) {
  134. self.compareProgress = Double(index) / Double(self.testFiles.count)
  135. }
  136. self.compareFinishedFiles.add(fileName);
  137. self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
  138. fileIndex += 1
  139. convertFileBlock(files);
  140. }
  141. }else {
  142. if (status == 0) {
  143. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档失败!\n",
  144. attributes:[.foregroundColor : NSColor.red]))
  145. }else if (status == -1 || status == -2) {
  146. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"文档无法打开!\n",
  147. attributes:[.foregroundColor : NSColor.red]))
  148. }else if (status == -3) {
  149. self.reportString?.append(NSMutableAttributedString.init(string: "【\(String(self.fileType())) - \(self.name())】文件 \"\(fName)\"转档中 Crash!\n",
  150. attributes:[.foregroundColor : NSColor.red]))
  151. }
  152. let index = self.testFiles.index(of: fileName);
  153. if (index != NSNotFound) {
  154. self.compareProgress = Double(index) / Double(self.testFiles.count)
  155. }
  156. self.compareFinishedFiles.add(fileName);
  157. self.testlog("对比完成:"+fileName, (self.compareProgress + self.convertProgress)/2.0)
  158. fileIndex += 1
  159. convertFileBlock(files);
  160. }
  161. }
  162. }
  163. convertFileBlock(files);
  164. }
  165. ///Compare
  166. /// Tools
  167. func appendErrorInfo(_ skipString:NSString, failString: NSString) {
  168. if skipString.length > 0 && failString.length > 0 {
  169. reportString?.append(NSMutableAttributedString.init(string: "对比字符串【\(skipString)】错识别为【\(failString)】\n",
  170. attributes:[.foregroundColor : NSColor.red]))
  171. }else if (skipString.length > 0) {
  172. reportString?.append(NSMutableAttributedString.init(string: "对比字符串【\(skipString)】未识别到\n",
  173. attributes:[.foregroundColor : NSColor.red]))
  174. }else if failString.length > 0 {
  175. reportString?.append(NSMutableAttributedString.init(string: "字符串【\(failString)】识别出错\n",
  176. attributes:[.foregroundColor : NSColor.red]))
  177. }
  178. }
  179. func attributeStringWith(_ skipString:NSString, failString: NSString) -> NSAttributedString {
  180. if skipString.length > 0 && failString.length > 0 {
  181. let strikethroughStyle = NSParagraphStyle.init()
  182. let attString = NSMutableAttributedString.init(string: skipString as String,
  183. attributes:[.foregroundColor : NSColor.red,
  184. .strikethroughStyle:NSNumber(integerLiteral: NSUnderlineStyle.single.rawValue),
  185. ])
  186. attString.append(NSMutableAttributedString.init(string: failString as String,
  187. attributes:[.foregroundColor : NSColor.blue,
  188. ]))
  189. return attString
  190. }else if (skipString.length > 0) {
  191. let strikethroughStyle = NSParagraphStyle.init()
  192. let attString = NSMutableAttributedString.init(string: skipString as String,
  193. attributes:[.foregroundColor : NSColor.red,
  194. .strikethroughStyle:NSNumber(integerLiteral: NSUnderlineStyle.single.rawValue),
  195. ])
  196. return attString
  197. }else if failString.length > 0 {
  198. let strikethroughStyle = NSParagraphStyle.init()
  199. let attString = NSMutableAttributedString.init(string: failString as String,
  200. attributes:[.foregroundColor : NSColor.blue,
  201. ])
  202. return attString
  203. }
  204. return NSAttributedString()
  205. }
  206. func replaceUnicodeString(_ string:NSString) -> NSString {//中
  207. let items = string.components(separatedBy: "\\u") as [NSString]
  208. var resultString = NSString()
  209. for item in items {
  210. if (item.contains("?")) {
  211. let unicodeValue = item.intValue
  212. let skipRange = item.range(of: "?")
  213. let nextString = item.substring(from: Int(skipRange.location + skipRange.length)) as NSString
  214. let bytes : [UInt8] = [UInt8(unicodeValue/256),UInt8(unicodeValue%256)]
  215. let data = NSData.init(bytes: bytes, length: 2)
  216. let unicodeString = NSString.init(data: data as Data, encoding: NSUnicodeStringEncoding)! as NSString
  217. resultString = resultString.appending(String("\(unicodeString)\(nextString)")) as NSString
  218. }else {
  219. resultString = resultString.appending(String(item)) as NSString
  220. }
  221. }
  222. return resultString
  223. }
  224. /// Compare
  225. func compareString(_ check:NSString, result:NSString, callback:@escaping (_ appAttr:NSAttributedString)->()) -> Double {
  226. // func compareString(_ check:NSString, result:NSString, failure:@escaping (_ skipString:NSString, _ failString:NSString)->()) -> Double {
  227. return autoreleasepool {
  228. var checkString = check
  229. var resultStr = result
  230. let maxSize = checkString.length
  231. var successCount = 0;
  232. /**
  233. (A0 = B0)
  234. - A-1 & B-1
  235. (A0 != B0) & (A0 in B) & (B0 in A)
  236. - 取 A0,B0最小 Range 值
  237. - 字符串裁剪对齐
  238. (A0 != B0) & (A0 in B)
  239. - 存储B0到识别错误缓存
  240. (A0 != B0) & (B0 in A)
  241. - 存储 A0到识别遗漏字符串
  242. (A0 != B0)
  243. - 分别存储 A0、B0到遗漏及错误字串
  244. */
  245. var skipString = NSString()
  246. var failString = NSString()
  247. while (checkString.length > 0 && resultStr.length > 0) {
  248. let subc = checkString.substring(to: 1) as NSString
  249. let subr = resultStr.substring(to: 1) as NSString
  250. let cRange = checkString.range(of: subr as String)
  251. let rRange = resultStr.range(of: subc as String)
  252. if subc.isEqual(to: subr) { // (A0 = B0)
  253. // Check Success
  254. callback(attributeStringWith(skipString, failString: failString))
  255. // failure(skipString, failString)
  256. // self.appendErrorInfo(skipString, failString: failString)
  257. skipString = NSString()
  258. failString = NSString()
  259. checkString = checkString.substring(from:1) as NSString
  260. resultStr = resultStr.substring(from:1) as NSString
  261. successCount = successCount + 1
  262. callback(NSAttributedString(string: subc as String))
  263. } else if (cRange.location != NSNotFound &&
  264. rRange.location != NSNotFound) {
  265. if (min(cRange.location, rRange.location) >= 2) {
  266. let nextc = checkString.substring(with: NSRange(location: 1, length: 1)) as NSString
  267. let nextr = resultStr.substring(with: NSRange(location: 1, length: 1)) as NSString
  268. let ncRange = checkString.range(of: nextr as String)
  269. let nrRange = resultStr.range(of: nextc as String)
  270. if (min(nrRange.location, ncRange.location) < min(cRange.location, rRange.location)) {
  271. if (ncRange.location < nrRange.location) {
  272. //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
  273. skipString = skipString.appending(subc as String) as NSString
  274. checkString = checkString.substring(from:1) as NSString
  275. }else {
  276. //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
  277. failString = failString.appending(subr as String) as NSString
  278. resultStr = resultStr.substring(from:1) as NSString
  279. }
  280. }else if (cRange.location < rRange.location) {
  281. //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
  282. skipString = skipString.appending(subc as String) as NSString
  283. checkString = checkString.substring(from:1) as NSString
  284. }else {
  285. //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
  286. failString = failString.appending(subr as String) as NSString
  287. resultStr = resultStr.substring(from:1) as NSString
  288. }
  289. }else {
  290. // var scale = (skipString.length > 0) ? (Float(checkString.length) / Float(skipString.length)) : Float(1.0)
  291. // if (checkString.length > skipString.length && cRange.location <= Int(Float(rRange.location)*scale)) {
  292. // //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
  293. // skipString = skipString.appending(subc as String) as NSString
  294. // checkString = checkString.substring(from:1) as NSString
  295. // }else if (checkString.length <= skipString.length && cRange.location > Int(Float(rRange.location)*scale)) {
  296. // failString = failString.appending(subr as String) as NSString
  297. // resultStr = resultStr.substring(from:1) as NSString
  298. // }else
  299. if (cRange.location < rRange.location) {
  300. //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
  301. skipString = skipString.appending(subc as String) as NSString
  302. checkString = checkString.substring(from:1) as NSString
  303. }else {
  304. //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
  305. failString = failString.appending(subr as String) as NSString
  306. resultStr = resultStr.substring(from:1) as NSString
  307. }
  308. // // self.appendErrorInfo(skipString, failString: failString)
  309. // callback(attributeStringWith(skipString, failString: failString))
  310. // // failure(skipString, failString)
  311. // skipString = NSString()
  312. // failString = NSString()
  313. //
  314. // // C:a[bcde]fghij
  315. // // R:f[klmnbvcx]a
  316. // if (cRange.location < rRange.location) {
  317. // let cacheString = checkString.substring(to:cRange.location + cRange.length)
  318. // callback(attributeStringWith(cacheString as NSString, failString: ""))
  319. // // failure(cacheString as NSString, "")
  320. // // self.reportString?.append(NSMutableAttributedString.init(string: "对照字符串【\(cacheString)】未识别到\n",
  321. // // attributes:[.foregroundColor : NSColor.red]))
  322. // checkString = checkString.substring(from:cRange.location) as NSString
  323. // }else {
  324. // let cacheString = resultStr.substring(to:rRange.location)
  325. // callback(attributeStringWith("", failString: cacheString as NSString))
  326. // // failure("", cacheString as NSString)
  327. // // self.reportString?.append(NSMutableAttributedString.init(string: "字符串【\(cacheString)】识别出错\n",
  328. // // attributes:[.foregroundColor : NSColor.red]))
  329. // resultStr = resultStr.substring(from:rRange.location + rRange.length) as NSString
  330. // }
  331. }
  332. }else if (cRange.location != NSNotFound) {
  333. //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
  334. skipString = skipString.appending(subc as String) as NSString
  335. checkString = checkString.substring(from:1) as NSString
  336. }else if (rRange.location != NSNotFound) {
  337. //‘subc' 字符串有在‘resultStr’中,但'subr'不在’checkString‘中,resultStr 往后推一
  338. failString = failString.appending(subr as String) as NSString
  339. resultStr = resultStr.substring(from:1) as NSString
  340. }else {
  341. // 两个子字串均未找到
  342. skipString = skipString.appending(subc as String) as NSString
  343. failString = failString.appending(subr as String) as NSString
  344. checkString = checkString.substring(from:1) as NSString
  345. resultStr = resultStr.substring(from:1) as NSString
  346. }
  347. }
  348. skipString = skipString.appending(checkString as String) as NSString
  349. failString = failString.appending(resultStr as String) as NSString
  350. // failure(skipString, failString)
  351. callback(attributeStringWith(skipString, failString: failString))
  352. callback(NSAttributedString(string: "\n"))
  353. let degree = (maxSize>1) ? Double(Float(successCount)/Float(maxSize) * 100) : 0
  354. return degree
  355. }
  356. }
  357. // Read File
  358. func readTextFile(_ filePath:NSString) -> String? {
  359. if NSArray(array: ["TXT", "txt"]).contains(filePath.pathExtension) {
  360. var checkString = try? NSString.init(contentsOfFile: filePath as String, encoding: NSUTF8StringEncoding)
  361. if (checkString != nil) {
  362. // checkString = checkString!.replacingOccurrences(of: "\n", with: "") as NSString
  363. // checkString = checkString!.replacingOccurrences(of: " ", with: "") as NSString
  364. return checkString! as String
  365. }
  366. return nil
  367. }else if NSArray(array: ["rtf", "RTF"]).contains(filePath.pathExtension) {
  368. // Load check file
  369. let checkData = NSData.init(contentsOfFile: filePath as String) as! Data
  370. var documentAttributes:NSDictionary!
  371. let checkAttString = NSAttributedString.init(rtf: checkData, documentAttributes: &documentAttributes)
  372. var checkString = NSString(string: checkAttString!.string) as NSString
  373. checkString = checkString.replacingOccurrences(of: "\n", with: "") as NSString
  374. checkString = checkString.replacingOccurrences(of: " ", with: "") as NSString
  375. // 常规 rtf 读取失败
  376. //使用框排进行读取
  377. if (checkString.length > 0) {
  378. return checkString as String?
  379. }
  380. var resultString = try? NSString.init(contentsOfFile: filePath as String, encoding: NSUTF8StringEncoding)
  381. if (nil != resultString && !resultString!.contains("\\shptxt\\shptxt")) {
  382. resultString = resultString!.replacingOccurrences(of: "\n", with: "") as NSString
  383. resultString = resultString!.replacingOccurrences(of: " ", with: "") as NSString
  384. return resultString! as String
  385. }
  386. //识别字符串 \shptxt\shptxt ... }
  387. let pageInfoStrings = resultString!.components(separatedBy: "\\shptxt\\shptxt") as NSArray
  388. var finalString = ""
  389. if pageInfoStrings.count > 0 {
  390. let subStrings = pageInfoStrings.subarray(with: NSMakeRange(1, Int(pageInfoStrings.count - 1))) as! [String]
  391. for pageInfoString in subStrings {
  392. let endRange = NSString(string: pageInfoString).range(of: "}")
  393. finalString = finalString.appending(NSString(string: pageInfoString).substring(to: endRange.location))
  394. }
  395. }
  396. //识别所有 【空格 ~ \】 之间的值,并进行缝合
  397. // Detect all strings between Spaces and \ and stitch
  398. let strings = finalString.components(separatedBy: " ")
  399. var resultStr = "" as NSString
  400. for str in strings {
  401. let markStr = str as NSString
  402. if (markStr.contains("\\f")) {
  403. let fRange = markStr.range(of: "\\f")
  404. let cRange = markStr.range(of: "\\c")
  405. let bRange = markStr.range(of: "\\b")
  406. let iRange = markStr.range(of: "\\i")
  407. let eRange = markStr.range(of: "\\e")
  408. let pRange = markStr.range(of: "\\p")
  409. let minPos = min(Int(fRange.location),
  410. Int(cRange.location),
  411. Int(bRange.location),
  412. Int(iRange.location),
  413. Int(eRange.location),
  414. Int(pRange.location))
  415. resultStr = resultStr.appending(markStr.substring(to: minPos)) as NSString
  416. }else {
  417. resultStr = resultStr.appending(markStr as String) as NSString
  418. }
  419. }
  420. resultStr = self.replaceUnicodeString(resultStr)
  421. resultStr = resultStr.replacingOccurrences(of: "\n", with: "") as NSString
  422. resultStr = resultStr.replacingOccurrences(of: " ", with: "") as NSString
  423. resultStr = resultStr.replacingOccurrences(of: "\\pard", with: "") as NSString
  424. resultStr = resultStr.replacingOccurrences(of: "\\par", with: "") as NSString
  425. return resultStr as String?
  426. }
  427. return nil
  428. }
  429. override func compareFiles() -> NSArray? {
  430. return nil
  431. }
  432. override func compareFiles(_ fileName: String) -> NSArray? {
  433. return nil
  434. }
  435. /**
  436. Replace the refrence image for next image check test
  437. */
  438. override func canUpdateRefImage() -> Bool {
  439. return false
  440. }
  441. override func updateRefImage() {
  442. }
  443. override func canUpdateRefImage(_ fileName:String) -> Bool {
  444. return false
  445. }
  446. override func updateRefImage(_ fileName:String) {
  447. }
  448. }