StripANSI removes ANSI escape codes from a string using a comprehensive byte scanner. It handles CSI sequences (\x1b[), OSC sequences (\x1b]), G0/G1 character set selections, keypad mode sequences, reset sequences, and other common 2-character escape sequences. This is more thorough than regex-base
(s string)
| 16 | // This is more thorough than regex-based approaches and correctly handles edge cases |
| 17 | // such as incomplete sequences, nested sequences, and non-standard terminal sequences. |
| 18 | func StripANSI(s string) string { |
| 19 | if s == "" { |
| 20 | return s |
| 21 | } |
| 22 | |
| 23 | ansiLog.Printf("StripANSI: input length=%d", len(s)) |
| 24 | |
| 25 | var result strings.Builder |
| 26 | result.Grow(len(s)) // Pre-allocate capacity for efficiency |
| 27 | |
| 28 | i := 0 |
| 29 | for i < len(s) { |
| 30 | if s[i] != '\x1b' { |
| 31 | result.WriteByte(s[i]) |
| 32 | i++ |
| 33 | continue |
| 34 | } |
| 35 | if i+1 >= len(s) { |
| 36 | i++ // ESC at end of string, skip it |
| 37 | continue |
| 38 | } |
| 39 | // Found ESC character, advance past the sequence |
| 40 | i = skipEscapeSequence(s, i) |
| 41 | } |
| 42 | |
| 43 | return result.String() |
| 44 | } |
| 45 | |
| 46 | // skipEscapeSequence advances past a complete ANSI escape sequence starting at i. |
| 47 | // i must point at '\x1b' and i+1 must be within the string. |