You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

escape.go 1.7KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package syntax
  2. import (
  3. "bytes"
  4. "strconv"
  5. "strings"
  6. "unicode"
  7. )
  8. func Escape(input string) string {
  9. b := &bytes.Buffer{}
  10. for _, r := range input {
  11. escape(b, r, false)
  12. }
  13. return b.String()
  14. }
  15. const meta = `\.+*?()|[]{}^$# `
  16. func escape(b *bytes.Buffer, r rune, force bool) {
  17. if unicode.IsPrint(r) {
  18. if strings.IndexRune(meta, r) >= 0 || force {
  19. b.WriteRune('\\')
  20. }
  21. b.WriteRune(r)
  22. return
  23. }
  24. switch r {
  25. case '\a':
  26. b.WriteString(`\a`)
  27. case '\f':
  28. b.WriteString(`\f`)
  29. case '\n':
  30. b.WriteString(`\n`)
  31. case '\r':
  32. b.WriteString(`\r`)
  33. case '\t':
  34. b.WriteString(`\t`)
  35. case '\v':
  36. b.WriteString(`\v`)
  37. default:
  38. if r < 0x100 {
  39. b.WriteString(`\x`)
  40. s := strconv.FormatInt(int64(r), 16)
  41. if len(s) == 1 {
  42. b.WriteRune('0')
  43. }
  44. b.WriteString(s)
  45. break
  46. }
  47. b.WriteString(`\u`)
  48. b.WriteString(strconv.FormatInt(int64(r), 16))
  49. }
  50. }
  51. func Unescape(input string) (string, error) {
  52. idx := strings.IndexRune(input, '\\')
  53. // no slashes means no unescape needed
  54. if idx == -1 {
  55. return input, nil
  56. }
  57. buf := bytes.NewBufferString(input[:idx])
  58. // get the runes for the rest of the string -- we're going full parser scan on this
  59. p := parser{}
  60. p.setPattern(input[idx+1:])
  61. for {
  62. if p.rightMost() {
  63. return "", p.getErr(ErrIllegalEndEscape)
  64. }
  65. r, err := p.scanCharEscape()
  66. if err != nil {
  67. return "", err
  68. }
  69. buf.WriteRune(r)
  70. // are we done?
  71. if p.rightMost() {
  72. return buf.String(), nil
  73. }
  74. r = p.moveRightGetChar()
  75. for r != '\\' {
  76. buf.WriteRune(r)
  77. if p.rightMost() {
  78. // we're done, no more slashes
  79. return buf.String(), nil
  80. }
  81. // keep scanning until we get another slash
  82. r = p.moveRightGetChar()
  83. }
  84. }
  85. }