diff --git a/Sources/Ghostwriter/ExtractionPattern.swift b/Sources/Ghostwriter/ExtractionPattern.swift index e8c154c..88a1bae 100644 --- a/Sources/Ghostwriter/ExtractionPattern.swift +++ b/Sources/Ghostwriter/ExtractionPattern.swift @@ -68,7 +68,12 @@ public class ExtractionPattern: Codable return nil } - print(match.numberOfRanges) + print("match.numberOfRanges - \(match.numberOfRanges)") + guard match.numberOfRanges > 1 else + { + return nil + } + let matchRange = match.range(at: 1) // Extract the substring matching the capture group diff --git a/Sources/Ghostwriter/Template.swift b/Sources/Ghostwriter/Template.swift index 57c5100..d3f0adc 100644 --- a/Sources/Ghostwriter/Template.swift +++ b/Sources/Ghostwriter/Template.swift @@ -34,25 +34,35 @@ public struct Template: Codable public func extract(_ index: Int, _ pattern: ExtractionPattern, _ source: String) throws -> (Template, String, Detail) { let oldText = "$\(index)" + + guard !source.isEmpty else + { + throw TemplateError.sourceIsEmpty + } // Find the substitution in the template - guard let index = self.string.index(of: oldText) else + guard let oldTextStringIndex = self.string.index(of: oldText) else { throw TemplateError.noSubstitution(oldText) } - - let templatePreludeIndex = self.string.index(index, offsetBy: oldText.count) - let sourcePreludeIndex = source.index(index, offsetBy: 0) - - let prelude = String(self.string[..= prelude.count else + { + throw TemplateError.sourceTooSmall(source) + } + + // Make sure that the text we got matches the beginning of our template guard source.starts(with: prelude) else { throw TemplateError.sourceDoesNotMatchTemplate } - - let templateRest = String(self.string[templatePreludeIndex...]) - let sourceRest = String(source[sourcePreludeIndex...]) + + // Extract the variable we are looking for + let sourceAfterwordStringIndex = source.index(oldTextStringIndex, offsetBy: 0) + let sourceRest = String(source[sourceAfterwordStringIndex...]) let result = try pattern.extract(sourceRest) let detail = try pattern.convert(result) @@ -61,10 +71,16 @@ public struct Template: Codable { throw TemplateError.sourceDoesNotMatchTemplate } + matchIndex = sourceRest.index(matchIndex, offsetBy: result.count) + // The variable we are looking for let sourceFinal = String(sourceRest[matchIndex...]) - + + // Return the part of the template which comes after the variable we extracted + let templateAfterwordStringIndex = self.string.index(oldTextStringIndex, offsetBy: oldText.count) + let templateRest = String(self.string[templateAfterwordStringIndex...]) + return (Template(templateRest), sourceFinal, detail) } } @@ -73,6 +89,8 @@ public enum TemplateError: Error { case sourceDoesNotMatchTemplate case noSubstitution(String) + case sourceTooSmall(String) + case sourceIsEmpty } extension StringProtocol { diff --git a/Tests/GhostwriterTests/GhostwriterTests.swift b/Tests/GhostwriterTests/GhostwriterTests.swift index 7076c37..6d4df24 100644 --- a/Tests/GhostwriterTests/GhostwriterTests.swift +++ b/Tests/GhostwriterTests/GhostwriterTests.swift @@ -34,7 +34,7 @@ final class GhostwriterTests: XCTestCase { let template = Template("a$1z") let patterns: [ExtractionPattern] = [ - ExtractionPattern(#"[0-9]+"#, .int) + ExtractionPattern(#"([0-9]+)"#, .int) ] let input = "a1z" @@ -48,7 +48,7 @@ final class GhostwriterTests: XCTestCase { let template = Template("a$1z") let patterns: [ExtractionPattern] = [ - ExtractionPattern(#"[A-Za-z0-9]"#, .string) + ExtractionPattern(#"([A-Za-z0-9])"#, .string) ] let input = "abz" @@ -62,7 +62,7 @@ final class GhostwriterTests: XCTestCase { let template = Template("a$1z") let patterns: [ExtractionPattern] = [ - ExtractionPattern(#"[0-9]+.[0-9]+"#, .float) + ExtractionPattern(#"([0-9]+.[0-9]+)"#, .float) ] let input = "a2.0z"