像BSD `ls` 一样中英文混排字符串(Python3)

本文介绍了一个Python库lscolumn,提供CJK字符对齐的字符串格式化功能,支持 BSD-ls 和 GNU-ls 风格,适用于终端宽度调整。展示了如何使用cjkljust函数进行字符串对齐,并通过pprint函数实现多行字符串的美观排列。
摘要由CSDN通过智能技术生成

这里有一个C语言实现的字符串打印功能。我没细看它支不支持中英文混排。我在此给一个Python3版的支持中英文混排的字符串打印代码。另见我的Gists:cjkjustfmtstrings_like_ls。下面的代码和Gists没有本质差别,只是我在下面新加了一点注释、精简了一点无关代码、以及添加了运行结果。

代码

中英文混排时的对齐函数cjkljust

try:
    # https://f.gallai.re/cjkwrap
    from cjkwrap import cjklen
except ImportError:
    import unicodedata

    def is_wide(char):
        return unicodedata.east_asian_width(char) in 'FW'

    def cjklen(string):
        return sum(2 if is_wide(char) else 1 for char in string)


def cjkljust(string, width, fillbyte=' '):
    """
    >>> cjkljust('hello', 10, '*')
    'hello*****'
    >>> cjkljust('你好world', 10, '*')
    '你好world*'
    >>> cjkljust('你好world', 1, '*')
    '你好world'
    """
    return string.ljust(len(string) + width - cjklen(string), fillbyte)

打印函数pprint

import math
import itertools
import shutil


def calc_layout(n_strings, total_width, column_width, width_between_cols):
    # expected_ncols * column_width +
    #     (expected_ncols - 1) * width_between_cols <= total_width
    #
    #   解得 expected_ncols <= (total_width + width_between_cols) /
    #                          (column_width + width_between_cols)
    # 因此 expected_ncols 最大为不等号右边的向下取整
    expected_ncols = math.floor((total_width + width_between_cols) /
                                (column_width + width_between_cols))
    expected_ncols = max(expected_ncols, 1)
    actual_nrows = math.ceil(n_strings / expected_ncols)
    actual_ncols = (n_strings - 1) // actual_nrows + 1
    return actual_nrows, actual_ncols


def pprint(strings, total_width=None, width_between_cols=1, file=None) -> None:
    """
    Pretty print list of strings like ``ls``.
    :param strings: list of strings
    :param total_width: the disposable total width, default to terminal width
    :param width_between_cols: width between columns, default to 1
    :param file: file handle to which to print, default to stdout
    """
    total_width = total_width or shutil.get_terminal_size().columns
    assert total_width >= 1, total_width
    assert width_between_cols >= 1, width_between_cols

    if not strings:
        return

    # column_width: BSD ls 的列宽为所有待打印字符串的最长长度
    column_width = max(map(cjklen, strings))
    nrows, ncols = calc_layout(
        len(strings), total_width, column_width, width_between_cols)
    columns = [[] for _ in range(ncols)]
    for i, s in enumerate(strings):
        columns[i // nrows].append(s)

    for row in itertools.zip_longest(*columns):
        padded_row = (cjkljust(s or '', column_width) for s in row)
        print((' ' * width_between_cols).join(padded_row), file=file)

运行

测试代码1:

pprint(['aaaaaaa', 'bbbb', 'ccccc你好ccc', 'dddddd', 'eeeeeeeeee',
        '再一次感谢', 'fff', 'g', 'hh', 'iiiiiiiiiii', 'jjjj'],
       total_width=80)

运行结果1:
运行结果1

测试代码2:

pprint(['aaaaaaa', 'bbbb', 'ccccc你好ccc', 'dddddd', 'eeeeeeeeee',
        '再一次感谢', 'fff', 'g', 'hh', 'iiiiiiiiiii', 'jjjj'],
       total_width=40)

运行结果2:
运行结果2


我发布了这个功能的Python库lscolumn,包括了BSD-ls和GNU-ls两种样式。欢迎试用:

pip install lscolumn
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值