From fba8cdcf301bd9d56831eba1db542c6e9feafdde Mon Sep 17 00:00:00 2001 From: Richard Kettelerij Date: Thu, 9 Jan 2025 16:35:26 +0100 Subject: [PATCH] fix: prevent endless loop for specific case. Also rewrite from recursive to imperative function. --- internal/etl/transform/subst_and_synonyms.go | 29 ++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/internal/etl/transform/subst_and_synonyms.go b/internal/etl/transform/subst_and_synonyms.go index 9d44b29..e3fe98d 100644 --- a/internal/etl/transform/subst_and_synonyms.go +++ b/internal/etl/transform/subst_and_synonyms.go @@ -40,7 +40,8 @@ func (s SubstAndSynonyms) generate(fieldValuesByName map[string]string) []map[st // Create map with for each key a slice of []values fieldValuesByNameWithAllValues[key] = allValues } - return generateAllCombinations(fieldValuesByNameWithAllValues) + combinations := generateAllCombinations(fieldValuesByNameWithAllValues) + return combinations } // Transform a map[string][]string into a []map[string]string using the cartesian product, i.e. @@ -82,19 +83,26 @@ func generateCombinations(keys []string, values [][]string) []map[string]string func extendValues(input []string, mapping map[string]string) []string { var results []string - results = append(results, input...) - for j := range input { + for len(input) > 0 { + // Pop the first element from the input slice + current := input[0] + input = input[1:] + + // Add the current string to the results + results = append(results, current) + + // Generate new strings based on the mapping for oldChar, newChar := range mapping { - if strings.Contains(input[j], oldChar) { - for i := 0; i < strings.Count(input[j], oldChar); i++ { - extendedInput := replaceNth(input[j], oldChar, newChar, i+1) - subCombinations := extendValues([]string{extendedInput}, mapping) - results = append(results, subCombinations...) + if strings.Contains(current, oldChar) { + for i := 0; i < strings.Count(current, oldChar); i++ { + extendedInput := replaceNth(current, oldChar, newChar, i+1) + input = append(input, extendedInput) } } } } + // Possible performance improvement here by avoiding duplicates in the first place return uniqueSlice(results) } @@ -105,6 +113,11 @@ func replaceNth(input, oldChar, newChar string, nthIndex int) string { for i := 0; i < len(input); i++ { if strings.HasPrefix(input[i:], oldChar) { + if strings.HasPrefix(newChar, oldChar) { + // skip to prevent endless loop (in calling function) for cases such as + // oldChar = "foo", newChar = "foos" and input = "foosball", which would otherwise result in "foosssssssssssssssball" + continue + } count++ if count == nthIndex { result.WriteString(newChar)