Files
controller-wisetopdataserver/python/biopro/util/text.py
T
2021-12-20 14:52:55 +08:00

276 lines
7.0 KiB
Python

from typing import Optional, Tuple, Union, overload, List, Any, TypeVar, IO, Iterable, Sequence, Dict, Callable
T = TypeVar('T')
@overload
def part_prefix(line: str, char: str, from_right=False) -> Tuple[Optional[str], str]:
pass
@overload
def part_prefix(line: str, char: str, missing: T, from_right=False) -> Tuple[Union[str, T], str]:
pass
def part_prefix(line: str, char: str, missing=None, from_right=False):
try:
if from_right:
i = line.rindex(char)
else:
i = line.index(char)
return line[:i], line[i + len(char):]
except ValueError:
return missing, line
@overload
def part_suffix(line: str, char: str, from_right=False) -> Tuple[str, Optional[str]]:
pass
@overload
def part_suffix(line: str, char: str, missing: T, from_right=False) -> Tuple[str, Union[str, T]]:
pass
def part_suffix(line: str, char: str, missing=None, from_right=False):
try:
if from_right:
i = line.rindex(char)
else:
i = line.index(char)
return line[:i], line[i + len(char):]
except ValueError:
return line, missing
def print_block(block: str, file: IO = None):
lines = block.split('\n')
if len(lines) == 0:
return
if len(lines[0]) != 0:
indent = len(lines[0]) - len(lines[0].lstrip())
elif len(lines[1]) != 0:
indent = len(lines[1]) - len(lines[1].lstrip())
else:
indent = 0
for i, line in enumerate(lines):
line = line[indent:]
if i == 0 and len(line) == 0:
continue
print(line, file=file)
def _line_max_length(ls: List[str]) -> int:
length = 0
for s in ls:
length = max(length, len(s))
return length
def list_padding(ls: List[str], ele: Optional[List[str]] = None, align_right=False, padding=' ', split=' '):
"""align"""
if ele is None:
length = _line_max_length(ls)
for i, ln in enumerate(ls):
ls[i] = ln + split + padding * (length - len(ln))
else:
if len(ls) != len(ele):
raise RuntimeError('size not match %d != %d' % (len(ls), len(ele)))
if align_right:
length = _line_max_length(ls)
ele_length = _line_max_length(ele)
for i in range(len(ls)):
ls[i] = ls[i] + padding * (length - len(ls[i])) + split + padding * (ele_length - len(ele[i])) + ele[i]
else:
length = _line_max_length(ls)
for i in range(len(ls)):
ls[i] = ls[i] + padding * (length - len(ls[i])) + split + ele[i]
def _expr_format_enclose(expr: str, from_index: int) -> Tuple[int, str]:
if expr[from_index] != '{':
raise ValueError('lost "{"')
i = expr.find('}', from_index)
if i < 0:
raise ValueError('lost "}"')
return i + 1, expr[from_index + 1: i]
def expr_format(expr: str, mapper: Callable[[str], Optional[str]]) -> str:
a = []
try:
p = 0
while True:
i = expr.index('%', p)
c = expr[i + 1]
j = i + 2
if c == '%':
a.append('%')
elif c == '?':
c = expr[i + 2]
if ord('A') <= ord(c) <= ord('Z'):
c = expr[i + 2:i + 4]
j = i + 4
else:
j = i + 3
j, e = _expr_format_enclose(expr, j)
r = mapper(c)
if r is None:
a.append('')
else:
a.append(e.replace('%', r))
else:
if ord('A') <= ord(c) <= ord('Z'):
c = expr[i + 1:i + 3]
j = i + 3
r = mapper(c)
if r is None:
r = ''
a.append(r)
p = i + 2
expr = expr[:i] + '%s' + expr[j:]
except ValueError:
pass
except IndexError as e:
raise ValueError('lost field') from e
return expr % tuple(a)
class Table:
def __init__(self, *title: str, column: int = None, align_right=True):
if len(title) == 0:
if column is None:
raise ValueError('lost column')
self._cols: List[List[str]] = [[] for _ in range(column)]
else:
self._cols: List[List[str]] = [[t] for t in title]
self._fmt: List[Dict[str, Any]] = [{'align_right': align_right} for _ in self._cols]
@property
def columns(self) -> int:
return len(self._cols)
@property
def rows(self) -> int:
return len(self._cols[0])
def get_column(self, text: str) -> Optional[int]:
for c in range(len(self._cols)):
if self._cols[c][0] == text:
return c
return None
def append(self, *content: Any):
for i, col in enumerate(self._cols):
try:
elem = content[i]
except IndexError:
col.append('')
else:
col.append(str(elem) if elem is not None else '')
def extend(self, content: Iterable[Sequence[Any]]):
for line in content:
for i, col in enumerate(self._cols):
try:
elem = line[i]
except IndexError:
col.append('')
else:
col.append(str(elem) if elem is not None else '')
def set_format(self,
column: Union[None, int, str, List[int], List[str]],
align_right=True,
padding=' ',
split=None):
f = {
'align_right': align_right,
'padding': padding,
}
if split is not None:
f['split'] = split
if column is None:
for c in range(self.columns):
self._fmt[c] = f
elif isinstance(column, int):
self._fmt[column] = f
elif isinstance(column, str):
c = self.get_column(column)
if c is not None:
self._fmt[c] = f
elif isinstance(column, (tuple, list)):
if len(column):
if isinstance(column[0], int):
for c in column:
self._fmt[c] = f
else:
for t in column:
c = self.get_column(t)
if c is not None:
self._fmt[c] = f
else:
raise ValueError('column : ' + str(t))
else:
raise TypeError('column')
def lines(self) -> List[str]:
ret = ['' for _ in self._cols[0]]
for i, col in enumerate(self._cols):
list_padding(ret, col, **self._fmt[i])
return ret
def print(self, indent='', file: IO = None):
for line in self.lines():
print(indent, line, sep='', file=file)
def dump(self, file: IO = None):
for r in range(len(self._cols[0])):
print(','.join(map(lambda col: col[r], self._cols)), file=file)