mirror of
https://github.com/mikefarah/yq.git
synced 2026-07-06 21:55:37 +00:00
Fixing escape charaters again 😢 #2517
This commit is contained in:
parent
5d0481c0d2
commit
9e0c5fd3c9
@ -187,15 +187,69 @@ func parseInt(numberString string) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func processEscapeCharacters(original string) string {
|
func processEscapeCharacters(original string) string {
|
||||||
value := original
|
if original == "" {
|
||||||
value = strings.ReplaceAll(value, "\\\"", "\"")
|
return original
|
||||||
value = strings.ReplaceAll(value, "\\n", "\n")
|
}
|
||||||
value = strings.ReplaceAll(value, "\\t", "\t")
|
|
||||||
value = strings.ReplaceAll(value, "\\r", "\r")
|
var result strings.Builder
|
||||||
value = strings.ReplaceAll(value, "\\f", "\f")
|
runes := []rune(original)
|
||||||
value = strings.ReplaceAll(value, "\\v", "\v")
|
|
||||||
value = strings.ReplaceAll(value, "\\b", "\b")
|
for i := 0; i < len(runes); i++ {
|
||||||
value = strings.ReplaceAll(value, "\\a", "\a")
|
if runes[i] == '\\' && i < len(runes)-1 {
|
||||||
|
next := runes[i+1]
|
||||||
|
switch next {
|
||||||
|
case '\\':
|
||||||
|
// Check if followed by opening bracket - if so, preserve both backslashes
|
||||||
|
// this is required for string interpolation to work correctly.
|
||||||
|
if i+2 < len(runes) && runes[i+2] == '(' {
|
||||||
|
// Preserve \\ when followed by (
|
||||||
|
result.WriteRune('\\')
|
||||||
|
result.WriteRune('\\')
|
||||||
|
i++ // Skip the next backslash (we'll process the ( normally on next iteration)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Escaped backslash: \\ -> \
|
||||||
|
result.WriteRune('\\')
|
||||||
|
i++ // Skip the next backslash
|
||||||
|
continue
|
||||||
|
case '"':
|
||||||
|
result.WriteRune('"')
|
||||||
|
i++ // Skip the quote
|
||||||
|
continue
|
||||||
|
case 'n':
|
||||||
|
result.WriteRune('\n')
|
||||||
|
i++ // Skip the 'n'
|
||||||
|
continue
|
||||||
|
case 't':
|
||||||
|
result.WriteRune('\t')
|
||||||
|
i++ // Skip the 't'
|
||||||
|
continue
|
||||||
|
case 'r':
|
||||||
|
result.WriteRune('\r')
|
||||||
|
i++ // Skip the 'r'
|
||||||
|
continue
|
||||||
|
case 'f':
|
||||||
|
result.WriteRune('\f')
|
||||||
|
i++ // Skip the 'f'
|
||||||
|
continue
|
||||||
|
case 'v':
|
||||||
|
result.WriteRune('\v')
|
||||||
|
i++ // Skip the 'v'
|
||||||
|
continue
|
||||||
|
case 'b':
|
||||||
|
result.WriteRune('\b')
|
||||||
|
i++ // Skip the 'b'
|
||||||
|
continue
|
||||||
|
case 'a':
|
||||||
|
result.WriteRune('\a')
|
||||||
|
i++ // Skip the 'a'
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.WriteRune(runes[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
value := result.String()
|
||||||
if value != original {
|
if value != original {
|
||||||
log.Debug("processEscapeCharacters from [%v] to [%v]", original, value)
|
log.Debug("processEscapeCharacters from [%v] to [%v]", original, value)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -408,3 +408,122 @@ func TestKindString(t *testing.T) {
|
|||||||
test.AssertResult(t, "AliasNode", KindString(AliasNode))
|
test.AssertResult(t, "AliasNode", KindString(AliasNode))
|
||||||
test.AssertResult(t, "unknown!", KindString(Kind(999))) // Invalid kind
|
test.AssertResult(t, "unknown!", KindString(Kind(999))) // Invalid kind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type processEscapeCharactersScenario struct {
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
}
|
||||||
|
|
||||||
|
var processEscapeCharactersScenarios = []processEscapeCharactersScenario{
|
||||||
|
{
|
||||||
|
input: "",
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "hello",
|
||||||
|
expected: "hello",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "\\\"",
|
||||||
|
expected: "\"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "hello\\\"world",
|
||||||
|
expected: "hello\"world",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "\\n",
|
||||||
|
expected: "\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "line1\\nline2",
|
||||||
|
expected: "line1\nline2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "\\t",
|
||||||
|
expected: "\t",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "hello\\tworld",
|
||||||
|
expected: "hello\tworld",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "\\r",
|
||||||
|
expected: "\r",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "hello\\rworld",
|
||||||
|
expected: "hello\rworld",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "\\f",
|
||||||
|
expected: "\f",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "hello\\fworld",
|
||||||
|
expected: "hello\fworld",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "\\v",
|
||||||
|
expected: "\v",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "hello\\vworld",
|
||||||
|
expected: "hello\vworld",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "\\b",
|
||||||
|
expected: "\b",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "hello\\bworld",
|
||||||
|
expected: "hello\bworld",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "\\a",
|
||||||
|
expected: "\a",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "hello\\aworld",
|
||||||
|
expected: "hello\aworld",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "\\\"\\n\\t\\r\\f\\v\\b\\a",
|
||||||
|
expected: "\"\n\t\r\f\v\b\a",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "multiple\\nlines\\twith\\ttabs",
|
||||||
|
expected: "multiple\nlines\twith\ttabs",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "quote\\\"here",
|
||||||
|
expected: "quote\"here",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "\\\\",
|
||||||
|
expected: "\\", // Backslash is processed: "\\\\" becomes "\\"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "\\\"test\\\"",
|
||||||
|
expected: "\"test\"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "a\\\\b",
|
||||||
|
expected: "a\\b", // Tests roundtrip: "a\\\\b" should become "a\\b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "Hi \\\\(.value)",
|
||||||
|
expected: "Hi \\\\(.value)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: `a\\b`,
|
||||||
|
expected: "a\\b",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcessEscapeCharacters(t *testing.T) {
|
||||||
|
for _, tt := range processEscapeCharactersScenarios {
|
||||||
|
actual := processEscapeCharacters(tt.input)
|
||||||
|
test.AssertResultComplexWithContext(t, tt.expected, actual, fmt.Sprintf("Input: %q", tt.input))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user