0

最大で「n」文字の長さの大きな文字列から「プレビュー テキスト」を表示する必要があります。残念ながら、これを処理する既存のモジュールが PyPi に見つかりませんでした。

適切な解決を望みます。以下のクイック&ダーティなソリューションは機能しますが、それほど効率的ではありません-多くの絶え間ない比較。誰かが改善する方法について考えを持っていますか? 正規表現を試しましたが、20分後にあきらめました。

私が思いついた不器用な解決策は、ほとんどのニーズに十分対応できます。これがより迅速かつ簡潔に実行できることはわかっています-そして、その方法を知りたいです.

sample = "This is a sample string and I would like to break it down by words, without exceeding max_chars."

def clean_cut( text , max_chars ):
    rval = []
    words = text.split(' ')
    for word in words:
        len_rval = len(' '.join(rval))
        if len_rval + 1 + len(word) > max_chars :
            break
        rval.append(word)
    return ' '.join(rval)

for i in ( 15, 16, 17,30,35):
    cutdown = clean_cut( sample , i )
    print "%s | %s" % ( i , cutdown )

そして出力は正しいです...

15 | This is a
16 | This is a sample
17 | This is a sample
30 | This is a sample string and I
35 | This is a sample string and I would
4

4 に答える 4

3

次の実装はあなたのために働くかもしれません

def clean_cut(st, end):
    st += ' ' #In case end > len(st)
    return st[:st[:end + 1].rfind(' ')]
for i in ( 15, 16, 17,30,35):
    cutdown = clean_cut( sample , i )
    print "%s | %s" % ( i , cutdown )

出力

15 | This is a
16 | This is a sample
17 | This is a sample
30 | This is a sample string and I
35 | This is a sample string and I would

ノート

textwrap と比較して、この実装は 50 倍高速です

>>> stmt_ab = """
for i in ( 15, 16, 17,30,35):
    cutdown = sample[:sample[:i + 1].rfind(' ')]
"""
>>> stmt_mg = """
for i in ( 15, 16, 17,30,35):
    cutdown =  textwrap.wrap(sample[:i+1],i)[0]
"""
>>> import timeit
>>> t1_ab = timeit.Timer(stmt=stmt_ab, setup = "from __main__ import sample")
>>> t1_mg = timeit.Timer(stmt=stmt_mg, setup = "from __main__ import sample, textwrap")
>>> t1_ab.timeit(10000)
0.10367805429780219
>>> t1_mg.timeit(10000)
5.597085870104877
>>> 
于 2013-01-25T20:09:05.917 に答える
1
def substring_match(length, string):
    return re.search('(.{1,%d}) ' % length, string).group(0).strip()

うまくいくはずです、私の些細なテストのためにやりました

于 2013-01-25T20:05:30.953 に答える
1

使用できますtextwrap

textwrap.wrap(yourstring[:length+1],length)[0]

文字列をスライスすることは特に必要ではありませんが、おそらく全体が少し効率的になります...

>>> textwrap.wrap(sample[:15+1],15)[0]
'This is a'
>>> textwrap.wrap(sample[:16+1],16)[0]
'This is a sample'
>>> textwrap.wrap(sample[:17+1],17)[0]
'This is a sample'
>>> textwrap.wrap(sample[:30+1],30)[0]
'This is a sample string and I'
>>> textwrap.wrap(sample[:35+1],35)[0]
'This is a sample string and I would'
于 2013-01-25T20:07:04.450 に答える
1

textwrap@mgilsonの回答によるポインターのように、あなたのために仕事をするための優れたライブラリ関数があります。

楽しみのために正規表現の回答を追加します。

^.{0,n}(?<=\S)(?!\S)

n を制限に置き換え、この正規表現を使用して最初の一致を検索します (最大一致は 1 つだけです)。スペース以外の文字はすべて単語の一部と見なします。肯定的な後読みは、一致の最後の文字が非スペースであることを確認し、否定的な先読みは、一致の最後の文字の後の文字がスペース文字または文字列の末尾であることを確認します。

文字列がスペース以外の長いシーケンスで始まるときに何かを一致させたい場合、この正規表現は文字制限でスペース以外の文字のシーケンスを壊します:

^.{0,n}(?<=\S)(?!\S)|^\S{n}
于 2013-01-25T20:18:52.790 に答える