From 3d732896499392b7de681dc5c482941df884e54d Mon Sep 17 00:00:00 2001 From: dankito Date: Tue, 19 May 2020 14:22:07 +0200 Subject: [PATCH] Added splitIntoPartsAndUnmaskCharByChar(). It's uglier but more efficient on strings with many separators --- .../banking/fints/messages/Separators.kt | 12 +++-- .../banking/fints/response/ResponseParser.kt | 51 +++++++++++++++++-- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/fints4k/src/main/kotlin/net/dankito/banking/fints/messages/Separators.kt b/fints4k/src/main/kotlin/net/dankito/banking/fints/messages/Separators.kt index d22137b9..af73a11d 100644 --- a/fints4k/src/main/kotlin/net/dankito/banking/fints/messages/Separators.kt +++ b/fints4k/src/main/kotlin/net/dankito/banking/fints/messages/Separators.kt @@ -4,16 +4,20 @@ package net.dankito.banking.fints.messages class Separators { companion object { - const val SegmentSeparator = "'" + const val SegmentSeparatorChar = '\'' + const val SegmentSeparator = SegmentSeparatorChar.toString() - const val DataElementGroupsSeparator = "+" + const val DataElementGroupsSeparatorChar = '+' + const val DataElementGroupsSeparator = DataElementGroupsSeparatorChar.toString() - const val DataElementsSeparator = ":" + const val DataElementsSeparatorChar = ':' + const val DataElementsSeparator = DataElementsSeparatorChar.toString() const val BinaryDataSeparatorChar = '@' const val BinaryDataSeparator = BinaryDataSeparatorChar.toString() - const val MaskingCharacter = "?" + const val MaskingCharacterChar = '?' + const val MaskingCharacter = MaskingCharacterChar.toString() val AllSeparators = listOf(DataElementsSeparator, DataElementGroupsSeparator, SegmentSeparator) diff --git a/fints4k/src/main/kotlin/net/dankito/banking/fints/response/ResponseParser.kt b/fints4k/src/main/kotlin/net/dankito/banking/fints/response/ResponseParser.kt index 2c9ac581..4d7e9af2 100644 --- a/fints4k/src/main/kotlin/net/dankito/banking/fints/response/ResponseParser.kt +++ b/fints4k/src/main/kotlin/net/dankito/banking/fints/response/ResponseParser.kt @@ -76,7 +76,7 @@ open class ResponseParser @JvmOverloads constructor( protected open fun parseSegment(segment: String): ReceivedSegment? { try { if (segment.isNotEmpty()) { // filter out empty lines - val dataElementGroups = splitIntoPartsAndUnmask(segment, Separators.DataElementGroupsSeparator) + val dataElementGroups = splitIntoPartsAndUnmaskCharByChar(segment, Separators.DataElementGroupsSeparatorChar) val segmentId = segment.substring(0, segment.indexOf(Separators.DataElementsSeparator)) @@ -715,7 +715,7 @@ open class ResponseParser @JvmOverloads constructor( } protected open fun getDataElements(dataElementGroup: String): List { - return splitIntoPartsAndUnmask(dataElementGroup, Separators.DataElementsSeparator) + return splitIntoPartsAndUnmaskCharByChar(dataElementGroup, Separators.DataElementsSeparatorChar) } /** @@ -742,12 +742,57 @@ open class ResponseParser @JvmOverloads constructor( elements.add(dataString.substring(startIndex)) } + val maskedSeparator = Separators.MaskingCharacter + separator + return elements.map { - if (it.contains(Separators.MaskingCharacter + separator)) it.replace(Separators.MaskingCharacter + separator, separator.toString()) + if (it.contains(maskedSeparator)) it.replace(maskedSeparator, separator) else it } } + protected open fun splitIntoPartsAndUnmaskCharByChar(dataString: String, separator: Char): List { + val binaryRanges = messageUtils.findBinaryDataRanges(dataString) + + var lastEndIndex = 0 + var partContainsMaskedSeparators = false + val parts = mutableListOf() + + for (i in dataString.indices) { + val char = dataString[i] + + if (char == separator && messageUtils.isInRange(i, binaryRanges) == false) { + if (dataString[i - 1] != Separators.MaskingCharacterChar) { + parts.add(extractPart(dataString, lastEndIndex, i, separator, partContainsMaskedSeparators)) + + lastEndIndex = i + 1 + partContainsMaskedSeparators = false + } + } + else if (char == Separators.MaskingCharacterChar && messageUtils.isInRange(i, binaryRanges) == false && i + 1 < dataString.length && dataString[i + 1] == separator) { + partContainsMaskedSeparators = true + } + } + + if (lastEndIndex != dataString.length) { + parts.add(extractPart(dataString, lastEndIndex, dataString.length, separator, partContainsMaskedSeparators)) + } + + return parts + } + + protected open fun extractPart(dataString: String, startIndex: Int, lastEndIndex: Int, separator: Char, + partContainsMaskedSeparators: Boolean): String { + + val part = dataString.substring(startIndex, lastEndIndex) + + if (partContainsMaskedSeparators) { + return part.replace(Separators.MaskingCharacter + separator, separator.toString()) + } + else { + return part + } + } + protected open fun parseStringToNullIfEmpty(string: String): String? { val parsedString = parseString(string)