Escape CSV cells that start with tab or carriage return
Trim-based formula detection skipped the old rule for leading control characters; check those bytes before trim. Signed-off-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Bryan FRIMIN <bryan@frimin.fr>
This commit is contained in:
@@ -41,13 +41,18 @@ func SanitizeRecord(record []string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SanitizeCell prefixes values that spreadsheet tools may interpret as formulas.
|
// SanitizeCell prefixes values that spreadsheet tools may interpret as formulas.
|
||||||
// Leading Unicode whitespace (including newlines) is ignored for detection only;
|
// Leading spaces are ignored for formula detection only; tab and carriage return
|
||||||
// the written cell keeps the original text with a leading single-quote escape.
|
// at the start are always escaped. The written cell keeps the original text with
|
||||||
|
// a leading single-quote when sanitization applies.
|
||||||
func SanitizeCell(value string) string {
|
func SanitizeCell(value string) string {
|
||||||
if value == "" {
|
if value == "" {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if spreadsheetLeadingControl(value[0]) {
|
||||||
|
return "'" + value
|
||||||
|
}
|
||||||
|
|
||||||
trimmed := strings.TrimLeftFunc(value, unicode.IsSpace)
|
trimmed := strings.TrimLeftFunc(value, unicode.IsSpace)
|
||||||
if trimmed == "" {
|
if trimmed == "" {
|
||||||
return value
|
return value
|
||||||
@@ -61,6 +66,15 @@ func SanitizeCell(value string) string {
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func spreadsheetLeadingControl(b byte) bool {
|
||||||
|
switch b {
|
||||||
|
case '\t', '\r':
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func formulaLeadingRune(r rune) bool {
|
func formulaLeadingRune(r rune) bool {
|
||||||
switch r {
|
switch r {
|
||||||
case '=', '+', '-', '@', '\\', '|', '%':
|
case '=', '+', '-', '@', '\\', '|', '%':
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ func TestSanitizeCell(t *testing.T) {
|
|||||||
assert.Equal(t, "'@sum", SanitizeCell("@sum"))
|
assert.Equal(t, "'@sum", SanitizeCell("@sum"))
|
||||||
assert.Equal(t, "' =1+1", SanitizeCell(" =1+1"))
|
assert.Equal(t, "' =1+1", SanitizeCell(" =1+1"))
|
||||||
assert.Equal(t, "'\n=1+1", SanitizeCell("\n=1+1"))
|
assert.Equal(t, "'\n=1+1", SanitizeCell("\n=1+1"))
|
||||||
|
assert.Equal(t, "'\tplain", SanitizeCell("\tplain"))
|
||||||
|
assert.Equal(t, "'\rhello", SanitizeCell("\rhello"))
|
||||||
assert.Equal(t, "'\\evil", SanitizeCell("\\evil"))
|
assert.Equal(t, "'\\evil", SanitizeCell("\\evil"))
|
||||||
assert.Equal(t, "'-5", SanitizeCell("-5"))
|
assert.Equal(t, "'-5", SanitizeCell("-5"))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user