From 16293762ec9c4999a19ee54a9fb836e921c0e1e3 Mon Sep 17 00:00:00 2001 From: Yosuke Mizutani Date: Sat, 7 Nov 2015 02:00:45 +0900 Subject: [PATCH] add unicode_ljust, unicode_rjust to string module --- src/mog_commons/__init__.py | 2 +- src/mog_commons/string.py | 40 ++++++++++++++++++++++++++++++-- tests/mog_commons/test_string.py | 32 +++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/mog_commons/__init__.py b/src/mog_commons/__init__.py index 60eb1af..d83c2a9 100644 --- a/src/mog_commons/__init__.py +++ b/src/mog_commons/__init__.py @@ -1 +1 @@ -__version__ = '0.1.18' +__version__ = '0.1.19' diff --git a/src/mog_commons/string.py b/src/mog_commons/string.py index bf9e53c..e01ac26 100644 --- a/src/mog_commons/string.py +++ b/src/mog_commons/string.py @@ -4,6 +4,7 @@ import six from mog_commons.collection import distinct +from mog_commons.types import * __all__ = [ 'is_unicode', @@ -29,6 +30,7 @@ def is_strlike(s): return isinstance(s, (six.string_types, bytes)) +@types(s=String) def unicode_width(s): if is_unicode(s): return sum(__unicode_width_mapping[east_asian_width(c)] for c in s) @@ -37,6 +39,7 @@ def unicode_width(s): return len(s) +@types(encoding=Option(String), errors=String) def to_unicode(s, encoding=None, errors='strict'): """ Make unicode string from any value @@ -58,6 +61,7 @@ def to_unicode(s, encoding=None, errors='strict'): return str(s) +@types(encoding=Option(String), errors=String) def to_str(s, encoding=None, errors='strict'): """ Make str from any value @@ -77,6 +81,7 @@ def to_str(s, encoding=None, errors='strict'): return str(s) +@types(encoding=Option(String), errors=String) def to_bytes(s, encoding=None, errors='strict'): """Convert string to bytes.""" encoding = encoding or 'utf-8' @@ -92,11 +97,40 @@ def to_bytes(s, encoding=None, errors='strict'): return str(s).encode(encoding, errors) -def edge_just(left, right, width, fillchar=' '): - padding = fillchar * max(1, width - unicode_width(left + right)) +@types(left=String, right=String, width=int, fillchar=String, min_padding_length=int) +def edge_just(left, right, width, fillchar=' ', min_padding_length=1): + """ + :param left: + :param right: + :param width: + :param fillchar: + :param min_padding_length: minimum padding length + :return: + """ + assert unicode_width(fillchar) == 1, 'fillchar must be single-width char' + padding = fillchar * max(min_padding_length, width - unicode_width(left + right)) return left + padding + right +@types(s=String, width=int, fillchar=String) +def unicode_ljust(s, width, fillchar=' '): + """ + Return Unicode string left-justified in a print-length width. + Padding is done using the specified fill character (default is a space). + """ + return edge_just(s, '', width, fillchar, 0) + + +@types(s=String, width=int, fillchar=String) +def unicode_rjust(s, width, fillchar=' '): + """ + Return Unicode string right-justified in a print-length width. + Padding is done using the specified fill character (default is a space). + """ + return edge_just('', s, width, fillchar, 0) + + +@types(s=String, width=int) def unicode_left(s, width): """Cut unicode string from left to fit a given width.""" i = 0 @@ -109,6 +143,7 @@ def unicode_left(s, width): return s[:i] +@types(s=String, width=int) def unicode_right(s, width): """Cut unicode string from right to fit a given width.""" i = len(s) @@ -121,6 +156,7 @@ def unicode_right(s, width): return s[i:] +@types(encoding_list=(String, ListOf(String))) def unicode_decode(data, encoding_list): """ Decode string data with one or more encodings, trying sequentially diff --git a/tests/mog_commons/test_string.py b/tests/mog_commons/test_string.py index 08366ba..df299ea 100644 --- a/tests/mog_commons/test_string.py +++ b/tests/mog_commons/test_string.py @@ -61,6 +61,38 @@ def test_edge_just_unicode(self): self.assertEqual(string.edge_just('あいu', 'えo', 10), 'あいu えo') self.assertEqual(string.edge_just('あいう', 'えお', 10), 'あいう えお') + def test_edge_just_error(self): + msg = 'fillchar must be single-width char' + self.assertRaisesMessage(AssertionError, msg, string.edge_just, '', '', 10, '') + self.assertRaisesMessage(AssertionError, msg, string.edge_just, '', '', 10, 'ab') + self.assertRaisesMessage(AssertionError, msg, string.edge_just, '', '', 10, 'あ') + + def test_unicode_ljust(self): + self.assertEqual(string.unicode_ljust('', 0), '') + self.assertEqual(string.unicode_ljust('', -1), '') + self.assertEqual(string.unicode_ljust('', 1), ' ') + self.assertEqual(string.unicode_ljust('', 10), ' ') + self.assertEqual(string.unicode_ljust('', 10, '.'), '..........') + self.assertEqual(string.unicode_ljust('abcde', 10), 'abcde ') + self.assertEqual(string.unicode_ljust('abcdefghij', 10), 'abcdefghij') + self.assertEqual(string.unicode_ljust('abcdefghijk', 10), 'abcdefghijk') + self.assertEqual(string.unicode_ljust('あいう', 10), 'あいう ') + self.assertEqual(string.unicode_ljust('あいうe', 10), 'あいうe ') + self.assertEqual(string.unicode_ljust('あいうeお', 10, '*'), 'あいうeお*') + + def test_unicode_rjust(self): + self.assertEqual(string.unicode_rjust('', 0), '') + self.assertEqual(string.unicode_rjust('', -1), '') + self.assertEqual(string.unicode_rjust('', 1), ' ') + self.assertEqual(string.unicode_rjust('', 10), ' ') + self.assertEqual(string.unicode_rjust('', 10, '.'), '..........') + self.assertEqual(string.unicode_rjust('abcde', 10), ' abcde') + self.assertEqual(string.unicode_rjust('abcdefghij', 10), 'abcdefghij') + self.assertEqual(string.unicode_rjust('abcdefghijk', 10), 'abcdefghijk') + self.assertEqual(string.unicode_rjust('あいう', 10), ' あいう') + self.assertEqual(string.unicode_rjust('あいうe', 10), ' あいうe') + self.assertEqual(string.unicode_rjust('あいうeお', 10, '*'), '*あいうeお') + def test_unicode_left(self): self.assertEqual(string.unicode_left('', 3), '') self.assertEqual(string.unicode_left('abcde', 3), 'abc')