You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
2.1 KiB
Python
85 lines
2.1 KiB
Python
#!/usr/bin/env python
|
|
# encoding: utf-8
|
|
|
|
"""Utilities to deal with text."""
|
|
|
|
|
|
def unescape(text):
|
|
"""Removes '\\' escaping from 'text'."""
|
|
rv = ''
|
|
i = 0
|
|
while i < len(text):
|
|
if i + 1 < len(text) and text[i] == '\\':
|
|
rv += text[i + 1]
|
|
i += 1
|
|
else:
|
|
rv += text[i]
|
|
i += 1
|
|
return rv
|
|
|
|
|
|
def escape(text, chars):
|
|
"""Escapes all characters in 'chars' in text using backspaces."""
|
|
rv = ''
|
|
for char in text:
|
|
if char in chars:
|
|
rv += '\\'
|
|
rv += char
|
|
return rv
|
|
|
|
|
|
def fill_in_whitespace(text):
|
|
"""Returns 'text' with escaped whitespace replaced through whitespaces."""
|
|
text = text.replace(r"\n", '\n')
|
|
text = text.replace(r"\t", '\t')
|
|
text = text.replace(r"\r", '\r')
|
|
text = text.replace(r"\a", '\a')
|
|
text = text.replace(r"\b", '\b')
|
|
return text
|
|
|
|
|
|
def head_tail(line):
|
|
"""Returns the first word in 'line' and the rest of 'line' or None if the
|
|
line is too short."""
|
|
generator = (t.strip() for t in line.split(None, 1))
|
|
head = next(generator).strip()
|
|
tail = ''
|
|
try:
|
|
tail = next(generator).strip()
|
|
except StopIteration:
|
|
pass
|
|
return head, tail
|
|
|
|
|
|
class LineIterator(object):
|
|
|
|
"""Convenience class that keeps track of line numbers in files."""
|
|
|
|
def __init__(self, text):
|
|
self._line_index = -1
|
|
self._lines = list(text.splitlines(True))
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def __next__(self):
|
|
"""Returns the next line."""
|
|
if self._line_index + 1 < len(self._lines):
|
|
self._line_index += 1
|
|
return self._lines[self._line_index]
|
|
raise StopIteration()
|
|
next = __next__ # for python2
|
|
|
|
@property
|
|
def line_index(self):
|
|
"""The 1 based line index in the current file."""
|
|
return self._line_index + 1
|
|
|
|
def peek(self):
|
|
"""Returns the next line (if there is any, otherwise None) without
|
|
advancing the iterator."""
|
|
try:
|
|
return self._lines[self._line_index + 1]
|
|
except IndexError:
|
|
return None
|