PageRenderTime 25ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/robot/utils/escaping.py

https://code.google.com/p/robotframework/
Python | 116 lines | 84 code | 17 blank | 15 comment | 18 complexity | aba662bc58c6525f1df50ceb0b939b9e MD5 | raw file
Possible License(s): Apache-2.0
  1. # Copyright 2008-2014 Nokia Solutions and Networks
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import re
  15. _SEQS_TO_BE_ESCAPED = ('\\', '${', '@{', '%{', '&{', '*{', '=')
  16. def escape(item):
  17. if not isinstance(item, basestring):
  18. return item
  19. for seq in _SEQS_TO_BE_ESCAPED:
  20. if seq in item:
  21. item = item.replace(seq, '\\' + seq)
  22. return item
  23. def unescape(item):
  24. if not (isinstance(item, basestring) and '\\' in item):
  25. return item
  26. return Unescaper().unescape(item)
  27. class Unescaper(object):
  28. _escaped = re.compile(r'(\\+)([^\\]*)')
  29. def unescape(self, string):
  30. return ''.join(self._yield_unescaped(string))
  31. def _yield_unescaped(self, string):
  32. while '\\' in string:
  33. finder = EscapeFinder(string)
  34. yield finder.before + finder.backslashes
  35. if finder.escaped and finder.text:
  36. yield self._unescape(finder.text)
  37. else:
  38. yield finder.text
  39. string = finder.after
  40. yield string
  41. def _unescape(self, text):
  42. try:
  43. escape = str(text[0])
  44. except UnicodeError:
  45. return text
  46. try:
  47. unescaper = getattr(self, '_unescaper_for_' + escape)
  48. except AttributeError:
  49. return text
  50. else:
  51. return unescaper(text[1:])
  52. def _unescaper_for_n(self, text):
  53. if text.startswith(' '):
  54. text = text[1:]
  55. return '\n' + text
  56. def _unescaper_for_r(self, text):
  57. return '\r' + text
  58. def _unescaper_for_t(self, text):
  59. return '\t' + text
  60. def _unescaper_for_x(self, text):
  61. return self._unescape_character(text, 2, 'x')
  62. def _unescaper_for_u(self, text):
  63. return self._unescape_character(text, 4, 'u')
  64. def _unescaper_for_U(self, text):
  65. return self._unescape_character(text, 8, 'U')
  66. def _unescape_character(self, text, length, escape):
  67. try:
  68. char = self._get_character(text[:length], length)
  69. except ValueError:
  70. return escape + text
  71. else:
  72. return char + text[length:]
  73. def _get_character(self, text, length):
  74. if len(text) < length or not text.isalnum():
  75. raise ValueError
  76. ordinal = int(text, 16)
  77. # No Unicode code points above 0x10FFFF
  78. if ordinal > 0x10FFFF:
  79. raise ValueError
  80. # unichr only supports ordinals up to 0xFFFF with narrow Python builds
  81. if ordinal > 0xFFFF:
  82. return eval("u'\\U%08x'" % ordinal)
  83. return unichr(ordinal)
  84. class EscapeFinder(object):
  85. _escaped = re.compile(r'(\\+)([^\\]*)')
  86. def __init__(self, string):
  87. res = self._escaped.search(string)
  88. self.before = string[:res.start()]
  89. escape_chars = len(res.group(1))
  90. self.backslashes = '\\' * (escape_chars // 2)
  91. self.escaped = bool(escape_chars % 2)
  92. self.text = res.group(2)
  93. self.after = string[res.end():]