def unique_id(prefix=None): """Generates a unique ID. If `prefix` is provided the ID will be appended to it. Args: prefix (str, optional): String prefix to prepend to ID value. Returns: str: ID value. Example: >>> unique_id() '1' >>> unique_id('id_') 'id_2' >>> unique_id() '3' .. versionadded:: 1.0.0 """ # pylint: disable=global-statement global ID_COUNTER ID_COUNTER += 1 return '{0}{1}'.format(pyd.to_string('' if prefix is None else prefix), pyd.to_string(ID_COUNTER))
def ends_with(text, target, position=None): """Checks if `text` ends with a given target string. Args: text (str): String to check. target (str): String to check for. position (int, optional): Position to search from. Defaults to end of `text`. Returns: bool: Whether `text` ends with `target`. Example: >>> ends_with('abc def', 'def') True >>> ends_with('abc def', 4) False .. versionadded:: 1.1.0 """ target = pyd.to_string(target) text = pyd.to_string(text) if position is None: position = len(text) return text[:position].endswith(target)
def js_replace(text, reg_exp, repl): """Replace `text` with `repl` using Javascript style regular expression to find matches. Args: text (str): String to evaluate. reg_exp (str): Javascript style regular expression. repl (str): Replacement string. Returns: str: Modified string. Example: >>> js_replace('aaBBcc', '/bb/', 'X') 'aaBBcc' >>> js_replace('aaBBcc', '/bb/i', 'X') 'aaXcc' >>> js_replace('aaBBccbb', '/bb/i', 'X') 'aaXccbb' >>> js_replace('aaBBccbb', '/bb/gi', 'X') 'aaXccX' .. versionadded:: 2.0.0 .. versionchanged:: 3.0.0 Reordered arguments to make `text` first. """ text = pyd.to_string(text) if not pyd.is_function(repl): repl = pyd.to_string(repl) return js_to_py_re_replace(reg_exp)(text, repl)
def starts_with(text, target, position=0): """Checks if `text` starts with a given target string. Args: text (str): String to check. target (str): String to check for. position (int, optional): Position to search from. Defaults to beginning of `text`. Returns: bool: Whether `text` starts with `target`. Example: >>> starts_with('abcdef', 'a') True >>> starts_with('abcdef', 'b') False >>> starts_with('abcdef', 'a', 1) False .. versionadded:: 1.1.0 """ text = pyd.to_string(text) target = pyd.to_string(target) return text[position:].startswith(target)
def replace(text, pattern, repl, ignore_case=False, count=0, escape=True): """Replace occurrences of `pattern` with `repl` in `text`. Optionally, ignore case when replacing. Optionally, set `count` to limit number of replacements. Args: text (str): String to replace. pattern (str): String pattern to find and replace. repl (str): String to substitute `pattern` with. ignore_clase (bool, optional): Whether to ignore case when replacing. Defaults to ``False``. count (int, optional): Maximum number of occurrences to replace. Defaults to ``0`` which replaces all. escape (bool, optional): Whether to escape `pattern` when searching. This is needed if a literal replacement is desired when `pattern` may contain special regular expression characters. Defaults to ``True``. Returns: str: Replaced string. Example: >>> replace('aabbcc', 'b', 'X') 'aaXXcc' >>> replace('aabbcc', 'B', 'X', ignore_case=True) 'aaXXcc' >>> replace('aabbcc', 'b', 'X', count=1) 'aaXbcc' >>> replace('aabbcc', '[ab]', 'X') 'aabbcc' >>> replace('aabbcc', '[ab]', 'X', escape=False) 'XXXXcc' .. versionadded:: 3.0.0 """ # pylint: disable=redefined-outer-name text = pyd.to_string(text) if pattern is None: return text pattern = pyd.to_string(pattern) if escape: pattern = re.escape(pattern) if not pyd.is_function(repl): repl = pyd.to_string(repl) flags = re.IGNORECASE if ignore_case else 0 # NOTE: Can't use `flags` argument to re.sub in Python 2.6 so have to use # this version instead. return re.compile(pattern, flags=flags).sub(repl, text, count=count)
def js_match(text, reg_exp): """Return list of matches using Javascript style regular expression. Args: text (str): String to evaluate. reg_exp (str): Javascript style regular expression. Returns: list: List of matches. Example: >>> js_match('aaBBcc', '/bb/') [] >>> js_match('aaBBcc', '/bb/i') ['BB'] >>> js_match('aaBBccbb', '/bb/i') ['BB'] >>> js_match('aaBBccbb', '/bb/gi') ['BB', 'bb'] .. versionadded:: 2.0.0 .. versionchanged:: 3.0.0 Reordered arguments to make `text` first. """ text = pyd.to_string(text) return js_to_py_re_find(reg_exp)(text)
def chop_right(text, step): """Like :func:`chop` except `text` is chopped from right. Args: text (str): String to chop. step (int): Interval to chop `text`. Returns: list: List of chopped characters. Example: >>> chop_right('abcdefg', 3) ['a', 'bcd', 'efg'] .. versionadded:: 3.0.0 """ if text is None: return [] text = pyd.to_string(text) if step <= 0: chopped = [text] else: text_len = len(text) chopped = [ text[-(i + step):text_len - i] for i in _range(0, text_len, step) ][::-1] return chopped
def chop(text, step): """Break up `text` into intervals of length `step`. Args: text (str): String to chop. step (int): Interval to chop `text`. Returns: list: List of chopped characters. If `text` is `None` an empty list is returned. Example: >>> chop('abcdefg', 3) ['abc', 'def', 'g'] .. versionadded:: 3.0.0 """ if text is None: return [] text = pyd.to_string(text) if step <= 0: chopped = [text] else: chopped = [text[i:i + step] for i in _range(0, len(text), step)] return chopped
def pad_right(text, length, chars=" "): """Pads `text` on the right side if it is shorter than the given padding length. The `chars` string may be truncated if the number of padding characters can't be evenly divided by the padding length. Args: text (str): String to pad. length (int): Amount to pad. chars (str, optional): Characters to pad with. Defaults to ``" "``. Returns: str: Padded string. Example: >>> pad_right('abc', 5) 'abc ' >>> pad_right('abc', 5, '.') 'abc..' .. versionadded:: 1.1.0 """ # pylint: disable=redefined-outer-name text = pyd.to_string(text) length = max((length, len(text))) return (text + repeat(chars, length))[:length]
def delimitedpathjoin(delimiter, *paths): """Join delimited path using specified delimiter. >>> assert delimitedpathjoin('.', '') == '' >>> assert delimitedpathjoin('.', '.') == '.' >>> assert delimitedpathjoin('.', ['', '.a']) == '.a' >>> assert delimitedpathjoin('.', ['a', '.']) == 'a.' >>> assert delimitedpathjoin('.', ['', '.a', '', '', 'b']) == '.a.b' >>> ret = '.a.b.c.d.e.' >>> assert delimitedpathjoin('.', ['.a.', 'b.', '.c', 'd', 'e.']) == ret >>> assert delimitedpathjoin('.', ['a', 'b', 'c']) == 'a.b.c' >>> ret = 'a.b.c.d.e.f' >>> assert delimitedpathjoin('.', ['a.b', '.c.d.', '.e.f']) == ret >>> ret = '.a.b.c.1.' >>> assert delimitedpathjoin('.', '.', 'a', 'b', 'c', 1, '.') == ret >>> assert delimitedpathjoin('.', []) == '' """ paths = [pyd.to_string(path) for path in pyd.flatten_deep(paths) if path] if len(paths) == 1: # Special case where there's no need to join anything. # Doing this because if path==[delimiter], then an extra delimiter # would be added if the else clause ran instead. path = paths[0] else: leading = delimiter if paths and paths[0].startswith(delimiter) else '' trailing = delimiter if paths and paths[-1].endswith(delimiter) else '' middle = delimiter.join( [path.strip(delimiter) for path in paths if path.strip(delimiter)]) path = ''.join([leading, middle, trailing]) return path
def join(array, separator=""): """Joins an iterable into a string using `separator` between each element. Args: array (iterable): Iterable to implode. separator (str, optional): Separator to using when joining. Defaults to ``''``. Returns: str: Joined string. Example: >>> join(['a', 'b', 'c']) == 'abc' True >>> join([1, 2, 3, 4], '&') == '1&2&3&4' True >>> join('abcdef', '-') == 'a-b-c-d-e-f' True See Also: - :func:`join` (main definition) - :func:`implode` (alias) .. versionadded:: 2.0.0 .. versionchanged:: 3.0.0 Modified :func:`implode` to have :func:`join` as main definition and :func:`implode` as alias. """ return pyd.to_string(separator).join(pyd.map_(array or (), pyd.to_string))
def delimitedpathjoin(delimiter, *paths): """Join delimited path using specified delimiter. >>> assert delimitedpathjoin('.', '') == '' >>> assert delimitedpathjoin('.', '.') == '.' >>> assert delimitedpathjoin('.', ['', '.a']) == '.a' >>> assert delimitedpathjoin('.', ['a', '.']) == 'a.' >>> assert delimitedpathjoin('.', ['', '.a', '', '', 'b']) == '.a.b' >>> ret = '.a.b.c.d.e.' >>> assert delimitedpathjoin('.', ['.a.', 'b.', '.c', 'd', 'e.']) == ret >>> assert delimitedpathjoin('.', ['a', 'b', 'c']) == 'a.b.c' >>> ret = 'a.b.c.d.e.f' >>> assert delimitedpathjoin('.', ['a.b', '.c.d.', '.e.f']) == ret >>> ret = '.a.b.c.1.' >>> assert delimitedpathjoin('.', '.', 'a', 'b', 'c', 1, '.') == ret >>> assert delimitedpathjoin('.', []) == '' """ paths = [pyd.to_string(path) for path in pyd.flatten_deep(paths) if path] if len(paths) == 1: # Special case where there's no need to join anything. # Doing this because if path==[delimiter], then an extra delimiter # would be added if the else clause ran instead. path = paths[0] else: leading = delimiter if paths and paths[0].startswith(delimiter) else "" trailing = delimiter if paths and paths[-1].endswith(delimiter) else "" middle = delimiter.join([path.strip(delimiter) for path in paths if path.strip(delimiter)]) path = "".join([leading, middle, trailing]) return path
def unquote(text, quote_char='"'): """Unquote `text` by removing `quote_char` if `text` begins and ends with it. Args: text (str): String to unquote. Returns: str: Unquoted string. Example: >>> unquote('"abc"') 'abc' >>> unquote('"abc"', '#') '"abc"' >>> unquote('#abc', '#') '#abc' >>> unquote('#abc#', '#') 'abc' .. versionadded:: 3.0.0 """ text = pyd.to_string(text) inner = text[1:-1] if text == "{0}{1}{0}".format(quote_char, inner): text = inner return text
def join(array, separator=''): """Joins an iterable into a string using `separator` between each element. Args: array (iterable): Iterable to implode. separator (str, optional): Separator to using when joining. Defaults to ``''``. Returns: str: Joined string. Example: >>> join(['a', 'b', 'c']) == 'abc' True >>> join([1, 2, 3, 4], '&') == '1&2&3&4' True >>> join('abcdef', '-') == 'a-b-c-d-e-f' True See Also: - :func:`join` (main definition) - :func:`implode` (alias) .. versionadded:: 2.0.0 .. versionchanged:: 3.0.0 Modified :func:`implode` to have :func:`join` as main definition and :func:`implode` as alias. """ return pyd.to_string(separator).join(pyd.map_(array or (), pyd.to_string))
def capitalize(text, strict=True): """Capitalizes the first character of `text`. Args: text (str): String to capitalize. strict (bool, optional): Whether to cast rest of string to lower case. Defaults to ``True``. Returns: str: Capitalized string. Example: >>> capitalize('once upon a TIME') 'Once upon a time' >>> capitalize('once upon a TIME', False) 'Once upon a TIME' .. versionadded:: 1.1.0 .. versionchanged:: 3.0.0 Added `strict` option. """ text = pyd.to_string(text) return (text.capitalize() if strict else text[:1].upper() + text[1:])
def chop(text, step): """Break up `text` into intervals of length `step`. Args: text (str): String to chop. step (int): Interval to chop `text`. Returns: list: List of chopped characters. If `text` is `None` an empty list is returned. Example: >>> chop('abcdefg', 3) ['abc', 'def', 'g'] .. versionadded:: 3.0.0 """ if text is None: return [] text = pyd.to_string(text) if step <= 0: chopped = [text] else: chopped = [text[i : i + step] for i in _range(0, len(text), step)] return chopped
def chop_right(text, step): """Like :func:`chop` except `text` is chopped from right. Args: text (str): String to chop. step (int): Interval to chop `text`. Returns: list: List of chopped characters. Example: >>> chop_right('abcdefg', 3) ['a', 'bcd', 'efg'] .. versionadded:: 3.0.0 """ if text is None: return [] text = pyd.to_string(text) if step <= 0: chopped = [text] else: text_len = len(text) chopped = [text[-(i + step) : text_len - i] for i in _range(0, text_len, step)][::-1] return chopped
def capitalize(text, strict=True): """Capitalizes the first character of `text`. Args: text (str): String to capitalize. strict (bool, optional): Whether to cast rest of string to lower case. Defaults to ``True``. Returns: str: Capitalized string. Example: >>> capitalize('once upon a TIME') 'Once upon a time' >>> capitalize('once upon a TIME', False) 'Once upon a TIME' .. versionadded:: 1.1.0 .. versionchanged:: 3.0.0 Added `strict` option. """ text = pyd.to_string(text) return text.capitalize() if strict else text[:1].upper() + text[1:]
def unquote(text, quote_char='"'): """Unquote `text` by removing `quote_char` if `text` begins and ends with it. Args: text (str): String to unquote. Returns: str: Unquoted string. Example: >>> unquote('"abc"') 'abc' >>> unquote('"abc"', '#') '"abc"' >>> unquote('#abc', '#') '#abc' >>> unquote('#abc#', '#') 'abc' .. versionadded:: 3.0.0 """ text = pyd.to_string(text) inner = text[1:-1] if text == '{0}{1}{0}'.format(quote_char, inner): text = inner return text
def slugify(text, separator="-"): """Convert `text` into an ASCII slug which can be used safely in URLs. Incoming `text` is converted to unicode and noramlzied using the ``NFKD`` form. This results in some accented characters being converted to their ASCII "equivalent" (e.g. ``é`` is converted to ``e``). Leading and trailing whitespace is trimmed and any remaining whitespace or other special characters without an ASCII equivalent are replaced with ``-``. Args: text (str): String to slugify. separator (str, optional): Separator to use. Defaults to ``'-'``. Returns: str: Slugified string. Example: >>> slugify('This is a slug.') == 'this-is-a-slug' True >>> slugify('This is a slug.', '+') == 'this+is+a+slug' True .. versionadded:: 3.0.0 """ normalized = unicodedata.normalize("NFKD", text_type(pyd.to_string(text))).encode("ascii", "ignore").decode("utf8") return separator_case(normalized, separator)
def re_replace(text, pattern, repl, ignore_case=False, count=0): """Replace occurrences of regex `pattern` with `repl` in `text`. Optionally, ignore case when replacing. Optionally, set `count` to limit number of replacements. Args: text (str): String to replace. pattern (str): String pattern to find and replace. repl (str): String to substitute `pattern` with. ignore_clase (bool, optional): Whether to ignore case when replacing. Defaults to ``False``. count (int, optional): Maximum number of occurrences to replace. Defaults to ``0`` which replaces all. Returns: str: Replaced string. Example: >>> re_replace('aabbcc', 'b', 'X') 'aaXXcc' >>> re_replace('aabbcc', 'B', 'X', ignore_case=True) 'aaXXcc' >>> re_replace('aabbcc', 'b', 'X', count=1) 'aaXbcc' >>> re_replace('aabbcc', '[ab]', 'X') 'XXXXcc' .. versionadded:: 3.0.0 """ if pattern is None: return pyd.to_string(text) return replace(text, pattern, repl, ignore_case=ignore_case, count=count, escape=False)
def pascal_case(text, strict=True): """Like :func:`camel_case` except the first letter is capitalized. Args: text (str): String to convert. strict (bool, optional): Whether to cast rest of string to lower case. Defaults to ``True``. Returns: str: String converted to class case. Example: >>> pascal_case('FOO BAR_bAz') 'FooBarBaz' >>> pascal_case('FOO BAR_bAz', False) 'FooBarBAz' .. versionadded:: 3.0.0 """ text = pyd.to_string(text) if strict: text = text.lower() return capitalize(camel_case(text), strict=False)
def slugify(text, separator='-'): """Convert `text` into an ASCII slug which can be used safely in URLs. Incoming `text` is converted to unicode and noramlzied using the ``NFKD`` form. This results in some accented characters being converted to their ASCII "equivalent" (e.g. ``é`` is converted to ``e``). Leading and trailing whitespace is trimmed and any remaining whitespace or other special characters without an ASCII equivalent are replaced with ``-``. Args: text (str): String to slugify. separator (str, optional): Separator to use. Defaults to ``'-'``. Returns: str: Slugified string. Example: >>> slugify('This is a slug.') == 'this-is-a-slug' True >>> slugify('This is a slug.', '+') == 'this+is+a+slug' True .. versionadded:: 3.0.0 """ normalized = (unicodedata.normalize('NFKD', text_type(pyd.to_string(text))).encode( 'ascii', 'ignore').decode('utf8')) return separator_case(normalized, separator)
def pad_right(text, length, chars=' '): """Pads `text` on the right side if it is shorter than the given padding length. The `chars` string may be truncated if the number of padding characters can't be evenly divided by the padding length. Args: text (str): String to pad. length (int): Amount to pad. chars (str, optional): Characters to pad with. Defaults to ``" "``. Returns: str: Padded string. Example: >>> pad_right('abc', 5) 'abc ' >>> pad_right('abc', 5, '.') 'abc..' .. versionadded:: 1.1.0 """ # pylint: disable=redefined-outer-name text = pyd.to_string(text) length = max((length, len(text))) return (text + repeat(chars, length))[:length]
def prune(text, length=0, omission='...'): """Like :func:`truncate` except it ensures that the pruned string doesn't exceed the original length, i.e., it avoids half-chopped words when truncating. If the pruned text + `omission` text is longer than the original text, then the original text is returned. Args: text (str): String to prune. length (int, optional): Target prune length. Defaults to ``0``. omission (str, optional): Omission text to append to the end of the pruned string. Defaults to ``'...'``. Returns: str: Pruned string. Example: >>> prune('Fe fi fo fum', 5) 'Fe fi...' >>> prune('Fe fi fo fum', 6) 'Fe fi...' >>> prune('Fe fi fo fum', 7) 'Fe fi...' >>> prune('Fe fi fo fum', 8, ',,,') 'Fe fi fo,,,' .. versionadded:: 3.0.0 """ text = pyd.to_string(text) text_len = len(text) omission_len = len(omission) if text_len <= length: return text # Replace non-alphanumeric chars with whitespace. def repl(match): # pylint: disable=missing-docstring char = match.group(0) return ' ' if char.upper() == char.lower() else char subtext = re_replace(text[:length + 1], r'.(?=\W*\w*$)', repl) if re.match(r'\w\w', subtext[-2:]): # Last two characters are alphanumeric. Remove last "word" from end of # string so that we prune to the next whole word. subtext = re_replace(subtext, r'\s*\S+$', '') else: # Last character (at least) is whitespace. So remove that character as # well as any other whitespace. subtext = subtext[:-1].rstrip() subtext_len = len(subtext) # Only add omission text if doing so will result in a string that is # equal two or smaller in length than the original. if (subtext_len + omission_len) <= text_len: text = text[:subtext_len] + omission return text
def prune(text, length=0, omission="..."): """Like :func:`truncate` except it ensures that the pruned string doesn't exceed the original length, i.e., it avoids half-chopped words when truncating. If the pruned text + `omission` text is longer than the original text, then the original text is returned. Args: text (str): String to prune. length (int, optional): Target prune length. Defaults to ``0``. omission (str, optional): Omission text to append to the end of the pruned string. Defaults to ``'...'``. Returns: str: Pruned string. Example: >>> prune('Fe fi fo fum', 5) 'Fe fi...' >>> prune('Fe fi fo fum', 6) 'Fe fi...' >>> prune('Fe fi fo fum', 7) 'Fe fi...' >>> prune('Fe fi fo fum', 8, ',,,') 'Fe fi fo,,,' .. versionadded:: 3.0.0 """ text = pyd.to_string(text) text_len = len(text) omission_len = len(omission) if text_len <= length: return text # Replace non-alphanumeric chars with whitespace. def repl(match): # pylint: disable=missing-docstring char = match.group(0) return " " if char.upper() == char.lower() else char subtext = re_replace(text[: length + 1], r".(?=\W*\w*$)", repl) if re.match(r"\w\w", subtext[-2:]): # Last two characters are alphanumeric. Remove last "word" from end of # string so that we prune to the next whole word. subtext = re_replace(subtext, r"\s*\S+$", "") else: # Last character (at least) is whitespace. So remove that character as # well as any other whitespace. subtext = subtext[:-1].rstrip() subtext_len = len(subtext) # Only add omission text if doing so will result in a string that is # equal two or smaller in length than the original. if (subtext_len + omission_len) <= text_len: text = text[:subtext_len] + omission return text
def truncate(text, length=30, omission="...", separator=None): """Truncates `text` if it is longer than the given maximum string length. The last characters of the truncated string are replaced with the omission string which defaults to ``...``. Args: text (str): String to truncate. length (int, optional): Maximum string length. Defaults to ``30``. omission (str, optional): String to indicate text is omitted. separator (mixed, optional): Separator pattern to truncate to. Returns: str: Truncated string. Example: >>> truncate('hello world', 5) 'he...' >>> truncate('hello world', 5, '..') 'hel..' >>> truncate('hello world', 10) 'hello w...' >>> truncate('hello world', 10, separator=' ') 'hello...' See Also: - :func:`truncate` (main definition) - :func:`trunc` (alias) .. versionadded:: 1.1.0 .. versionchanged:: 3.0.0 Made :func:`truncate` main function definition and added :func:`trunc` as alias. """ text = pyd.to_string(text) if len(text) <= length: return text omission_len = len(omission) text_len = length - omission_len text = text[:text_len] trunc_len = len(text) if pyd.is_string(separator): trunc_len = text.rfind(separator) elif pyd.is_re(separator): last = None for match in separator.finditer(text): last = match if last is not None: trunc_len = last.start() return text[:trunc_len] + omission
def truncate(text, length=30, omission='...', separator=None): """Truncates `text` if it is longer than the given maximum string length. The last characters of the truncated string are replaced with the omission string which defaults to ``...``. Args: text (str): String to truncate. length (int, optional): Maximum string length. Defaults to ``30``. omission (str, optional): String to indicate text is omitted. separator (mixed, optional): Separator pattern to truncate to. Returns: str: Truncated string. Example: >>> truncate('hello world', 5) 'he...' >>> truncate('hello world', 5, '..') 'hel..' >>> truncate('hello world', 10) 'hello w...' >>> truncate('hello world', 10, separator=' ') 'hello...' See Also: - :func:`truncate` (main definition) - :func:`trunc` (alias) .. versionadded:: 1.1.0 .. versionchanged:: 3.0.0 Made :func:`truncate` main function definition and added :func:`trunc` as alias. """ text = pyd.to_string(text) if len(text) <= length: return text omission_len = len(omission) text_len = length - omission_len text = text[:text_len] trunc_len = len(text) if pyd.is_string(separator): trunc_len = text.rfind(separator) elif pyd.is_re(separator): last = None for match in separator.finditer(text): last = match if last is not None: trunc_len = last.start() return text[:trunc_len] + omission
def series_phrase(items, separator=", ", last_separator=" and ", serial=False): """Join items into a grammatical series phrase, e.g., ``"item1, item2, item3 and item4"``. Args: items (list): List of string items to join. separator (str, optional): Item separator. Defaults to ``', '``. last_separator (str, optional): Last item separator. Defaults to ``' and '``. serial (bool, optional): Whether to include `separator` with `last_separator` when number of items is greater than 2. Defaults to ``False``. Returns: str: Joined string. Example: Example: >>> series_phrase(['apples', 'bananas', 'peaches']) 'apples, bananas and peaches' >>> series_phrase(['apples', 'bananas', 'peaches'], serial=True) 'apples, bananas, and peaches' >>> series_phrase(['apples', 'bananas', 'peaches'], '; ', ', or ') 'apples; bananas, or peaches' .. versionadded:: 3.0.0 """ items = pyd.chain(items).map(pyd.to_string).compact().value() item_count = len(items) separator = pyd.to_string(separator) last_separator = pyd.to_string(last_separator) if item_count > 2 and serial: last_separator = separator.rstrip() + last_separator if item_count >= 2: items = items[:-2] + [last_separator.join(items[-2:])] return separator.join(items)
def series_phrase(items, separator=', ', last_separator=' and ', serial=False): """Join items into a grammatical series phrase, e.g., ``"item1, item2, item3 and item4"``. Args: items (list): List of string items to join. separator (str, optional): Item separator. Defaults to ``', '``. last_separator (str, optional): Last item separator. Defaults to ``' and '``. serial (bool, optional): Whether to include `separator` with `last_separator` when number of items is greater than 2. Defaults to ``False``. Returns: str: Joined string. Example: Example: >>> series_phrase(['apples', 'bananas', 'peaches']) 'apples, bananas and peaches' >>> series_phrase(['apples', 'bananas', 'peaches'], serial=True) 'apples, bananas, and peaches' >>> series_phrase(['apples', 'bananas', 'peaches'], '; ', ', or ') 'apples; bananas, or peaches' .. versionadded:: 3.0.0 """ items = pyd.chain(items).map(pyd.to_string).compact().value() item_count = len(items) separator = pyd.to_string(separator) last_separator = pyd.to_string(last_separator) if item_count > 2 and serial: last_separator = separator.rstrip() + last_separator if item_count >= 2: items = items[:-2] + [last_separator.join(items[-2:])] return separator.join(items)
def surround(text, wrapper): """Surround a string with another string. Args: text (str): String to surround with `wrapper`. wrapper (str): String by which `text` is to be surrounded. Returns: str: Surrounded string. Example: >>> surround('abc', '"') '"abc"' >>> surround('abc', '!') '!abc!' .. versionadded:: 2.4.0 """ return '{1}{0}{1}'.format(pyd.to_string(text), pyd.to_string(wrapper))
def surround(text, wrapper): """Surround a string with another string. Args: text (str): String to surround with `wrapper`. wrapper (str): String by which `text` is to be surrounded. Returns: str: Surrounded string. Example: >>> surround('abc', '"') '"abc"' >>> surround('abc', '!') '!abc!' .. versionadded:: 2.4.0 """ return "{1}{0}{1}".format(pyd.to_string(text), pyd.to_string(wrapper))
def insert_substr(text, index, subtext): """Insert `subtext` in `text` starting at position `index`. Args: text (str): String to add substring to. index (int): String index to insert into. subtext (str): String to insert. Returns: str: Modified string. Example: >>> insert_substr('abcdef', 3, '--') 'abc--def' .. versionadded:: 3.0.0 """ text = pyd.to_string(text) subtext = pyd.to_string(subtext) return text[:index] + subtext + text[index:]
def has_substr(text, subtext): """Returns whether `subtext` is included in `text`. Args: text (str): String to search. subtext (str): String to search for. Returns: bool: Whether `subtext` is found in `text`. Example: >>> has_substr('abcdef', 'bc') True >>> has_substr('abcdef', 'bb') False .. versionadded:: 3.0.0 """ text = pyd.to_string(text) subtext = pyd.to_string(subtext) return text.find(subtext) >= 0
def count_substr(text, subtext): """Count the occurrences of `subtext` in `text`. Args: text (str): Source string to count from. subtext (str): String to count. Returns: int: Number of occurrences of `subtext` in `text`. Example: >>> count_substr('aabbccddaabbccdd', 'bc') 2 ..versionadded:: 3.0.0 """ if text is None or subtext is None: return 0 text = pyd.to_string(text) subtext = pyd.to_string(subtext) return text.count(subtext)
def count_substr(text, subtext): """Count the occurrences of `subtext` in `text`. Args: text (str): Source string to count from. subtext (str): String to count. Returns: int: Number of occurrences of `subtext` in `text`. Example: >>> count_substr('aabbccddaabbccdd', 'bc') 2 .. versionadded:: 3.0.0 """ if text is None or subtext is None: return 0 text = pyd.to_string(text) subtext = pyd.to_string(subtext) return text.count(subtext)
def ensure_ends_with(text, suffix): """Append a given suffix to a string, but only if the source string does not end with that suffix. Args: text (str): Source string to append `suffix` to. suffix (str): String to append to the source string if the source string does not end with `suffix`. Returns: str: source string possibly extended by `suffix`. Example: >>> ensure_ends_with('foo bar', '!') 'foo bar!' >>> ensure_ends_with('foo bar!', '!') 'foo bar!' .. versionadded:: 2.4.0 """ text = pyd.to_string(text) suffix = pyd.to_string(suffix) return text if text.endswith(suffix) else "{0}{1}".format(text, suffix)
def ensure_ends_with(text, suffix): """Append a given suffix to a string, but only if the source string does not end with that suffix. Args: text (str): Source string to append `suffix` to. suffix (str): String to append to the source string if the source string does not end with `suffix`. Returns: str: source string possibly extended by `suffix`. Example: >>> ensure_ends_with('foo bar', '!') 'foo bar!' >>> ensure_ends_with('foo bar!', '!') 'foo bar!' .. versionadded:: 2.4.0 """ text = pyd.to_string(text) suffix = pyd.to_string(suffix) return text if text.endswith(suffix) else '{0}{1}'.format(text, suffix)
def ensure_starts_with(text, prefix): """Prepend a given prefix to a string, but only if the source string does not start with that prefix. Args: text (str): Source string to prepend `prefix` to. suffix (str): String to prepend to the source string if the source string does not start with `prefix`. Returns: str: source string possibly prefixed by `prefix` Example: >>> ensure_starts_with('foo bar', 'Oh my! ') 'Oh my! foo bar' >>> ensure_starts_with('Oh my! foo bar', 'Oh my! ') 'Oh my! foo bar' .. versionadded:: 2.4.0 """ text = pyd.to_string(text) prefix = pyd.to_string(prefix) return text if text.startswith(prefix) else '{1}{0}'.format(text, prefix)
def ensure_starts_with(text, prefix): """Prepend a given prefix to a string, but only if the source string does not start with that prefix. Args: text (str): Source string to prepend `prefix` to. suffix (str): String to prepend to the source string if the source string does not start with `prefix`. Returns: str: source string possibly prefixed by `prefix` Example: >>> ensure_starts_with('foo bar', 'Oh my! ') 'Oh my! foo bar' >>> ensure_starts_with('Oh my! foo bar', 'Oh my! ') 'Oh my! foo bar' .. versionadded:: 2.4.0 """ text = pyd.to_string(text) prefix = pyd.to_string(prefix) return text if text.startswith(prefix) else "{1}{0}".format(text, prefix)
def start_case(text): """Convert `text` to start case. Args: text (str): String to convert. Returns: str: String converted to start case. Example: >>> start_case("fooBar") 'Foo Bar' .. versionadded:: 3.1.0 """ text = pyd.to_string(text) return ' '.join(capitalize(word, strict=False) for word in words(text))
def swap_case(text): """Swap case of `text` characters. Args: text (str): String to swap case. Returns: str: String with swapped case. Example: >>> swap_case('aBcDeF') 'AbCdEf' .. versionadded:: 3.0.0 """ text = pyd.to_string(text) return text.swapcase()
def lines(text): r"""Split lines in `text` into an array. Args: text (str): String to split. Returns: list: String split by lines. Example: >>> lines('a\nb\r\nc') ['a', 'b', 'c'] .. versionadded:: 3.0.0 """ text = pyd.to_string(text) return text.splitlines()
def chars(text): """Split `text` into a list of single characters. Args: text (str): String to split up. Returns: list: List of individual characters. Example: >>> chars('onetwo') ['o', 'n', 'e', 't', 'w', 'o'] .. versionadded:: 3.0.0 """ text = pyd.to_string(text) return list(text)
def clean(text): """Trim and replace multiple spaces with a single space. Args: text (str): String to clean. Returns: str: Cleaned string. Example: >>> clean('a b c d') 'a b c d' .. versionadded:: 3.0.0 """ text = pyd.to_string(text) return ' '.join(pyd.compact(text.split()))
def decapitalize(text): """Decaptitalizes the first character of `text`. Args: text (str): String to decapitalize. Returns: str: Decapitalized string. Example: >>> decapitalize('FOO BAR') 'fOO BAR' .. versionadded:: 3.0.0 """ text = pyd.to_string(text) return text[:1].lower() + text[1:]
def clean(text): """Trim and replace multiple spaces with a single space. Args: text (str): String to clean. Returns: str: Cleaned string. Example: >>> clean('a b c d') 'a b c d' ..versionadded:: 3.0.0 """ text = pyd.to_string(text) return " ".join(pyd.compact(text.split()))