Initial import from Docker volume
This commit is contained in:
123
tools/string_.py
Executable file
123
tools/string_.py
Executable file
@@ -0,0 +1,123 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
# Code come from python-Levenshtein
|
||||
|
||||
__all__ = ['StringMatcher', 'StringPartitioned', 'LazyString']
|
||||
|
||||
from warnings import warn
|
||||
|
||||
try:
|
||||
from Levenshtein import distance, editops, matching_blocks, opcodes, ratio
|
||||
|
||||
class StringMatcher:
|
||||
"""A SequenceMatcher-like class built on the top of Levenshtein"""
|
||||
|
||||
def _reset_cache(self):
|
||||
self._ratio = self._distance = None
|
||||
self._opcodes = self._editops = self._matching_blocks = None
|
||||
|
||||
def __init__(self, isjunk=None, seq1='', seq2=''):
|
||||
if isjunk:
|
||||
warn("isjunk not NOT implemented, it will be ignored")
|
||||
self._str1, self._str2 = seq1, seq2
|
||||
self._reset_cache()
|
||||
|
||||
def set_seqs(self, seq1, seq2):
|
||||
self._str1, self._str2 = seq1, seq2
|
||||
self._reset_cache()
|
||||
|
||||
def set_seq1(self, seq1):
|
||||
self._str1 = seq1
|
||||
self._reset_cache()
|
||||
|
||||
def set_seq2(self, seq2):
|
||||
self._str2 = seq2
|
||||
self._reset_cache()
|
||||
|
||||
def get_opcodes(self):
|
||||
if not self._opcodes:
|
||||
if self._editops:
|
||||
self._opcodes = opcodes(
|
||||
self._editops, self._str1, self._str2)
|
||||
else:
|
||||
self._opcodes = opcodes(self._str1, self._str2)
|
||||
return self._opcodes
|
||||
|
||||
def get_editops(self):
|
||||
if not self._editops:
|
||||
if self._opcodes:
|
||||
self._editops = editops(
|
||||
self._opcodes, self._str1, self._str2)
|
||||
else:
|
||||
self._editops = editops(self._str1, self._str2)
|
||||
return self._editops
|
||||
|
||||
def get_matching_blocks(self):
|
||||
if not self._matching_blocks:
|
||||
self._matching_blocks = matching_blocks(self.get_opcodes(),
|
||||
self._str1, self._str2)
|
||||
return self._matching_blocks
|
||||
|
||||
def ratio(self):
|
||||
if not self._ratio:
|
||||
self._ratio = ratio(self._str1, self._str2)
|
||||
return self._ratio
|
||||
|
||||
def quick_ratio(self):
|
||||
# This is usually quick enough :o)
|
||||
if not self._ratio:
|
||||
self._ratio = ratio(self._str1, self._str2)
|
||||
return self._ratio
|
||||
|
||||
def real_quick_ratio(self):
|
||||
len1, len2 = len(self._str1), len(self._str2)
|
||||
return 2.0 * min(len1, len2) / (len1 + len2)
|
||||
|
||||
def distance(self):
|
||||
if not self._distance:
|
||||
self._distance = distance(self._str1, self._str2)
|
||||
return self._distance
|
||||
except ImportError:
|
||||
from difflib import SequenceMatcher as StringMatcher
|
||||
|
||||
|
||||
class StringPartitioned(str):
|
||||
"A string subclass that stores parts that composes itself."
|
||||
__slots__ = ('_parts',)
|
||||
|
||||
def __init__(self, base):
|
||||
super().__init__()
|
||||
if isinstance(base, StringPartitioned):
|
||||
self._parts = base._parts
|
||||
else:
|
||||
self._parts = (base,)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._parts)
|
||||
|
||||
def __add__(self, other):
|
||||
new = self.__class__(str(self) + other)
|
||||
new._parts = self._parts + (other,)
|
||||
return new
|
||||
|
||||
def __radd__(self, other):
|
||||
new = self.__class__(other + str(self))
|
||||
new._parts = (other,) + self._parts
|
||||
return new
|
||||
|
||||
|
||||
class LazyString():
|
||||
def __init__(self, func, *args, **kwargs):
|
||||
self._func = func
|
||||
self._args = args
|
||||
self._kwargs = kwargs
|
||||
|
||||
def __str__(self):
|
||||
return self._func(*self._args, **self._kwargs)
|
||||
|
||||
def __add__(self, other):
|
||||
return str(self) + other
|
||||
|
||||
def __radd__(self, other):
|
||||
return other + str(self)
|
||||
Reference in New Issue
Block a user