def smart_truncate(string, max_length=0, word_boundary=False, separator=' ',
    save_order=False):
    """
    Truncate a string.
    :param string: string for modification
    :param max_length: output string length
    :param word_boundary:
    :param save_order: if True then word order of output string is like input string
    :param separator: separator between words
    :return:
    """
    string = string.strip(separator)
    if not max_length:
        return string
    if len(string) < max_length:
        return string
    if not word_boundary:
        return string[:max_length].strip(separator)
    if separator not in string:
        return string[:max_length]
    truncated = ''
    for word in string.split(separator):
        if word:
            next_len = len(truncated) + len(word)
            if next_len < max_length:
                truncated += '{0}{1}'.format(word, separator)
            elif next_len == max_length:
                truncated += '{0}'.format(word)
                break
            elif save_order:
                break
    if not truncated:
        truncated = string[:max_length]
    return truncated.strip(separator)
