2009-11-15 19 views
10

文字列を取得して140文字に短縮する必要があります。現在Python:単語境界でユニコード文字列を分割する

私がやっている:

if len(tweet) > 140: 
    tweet = re.sub(r"\s+", " ", tweet) #normalize space 
    footer = "… " + utils.shorten_urls(post['url']) 
    avail = 140 - len(footer) 
    words = tweet.split() 
    result = "" 
    for word in words: 
     word += " " 
     if len(word) > avail: 
      break 
     result += word 
     avail -= len(word) 
    tweet = (result + footer).strip() 
    assert len(tweet) <= 140 

は、これは英語のために素晴らしい作品、そしてストリングスなどの英語、しかしtweet.split()はただ一つの配列を返しますので、中国の文字列のために失敗します。

>>> s = u"简讯:新華社報道,美國總統奧巴馬乘坐的「空軍一號」專機晚上10時42分進入上海空域,預計約30分鐘後抵達浦東國際機場,開展他上任後首次訪華之旅。" 
>>> s 
u'\u7b80\u8baf\uff1a\u65b0\u83ef\u793e\u5831\u9053\uff0c\u7f8e\u570b\u7e3d\u7d71\u5967\u5df4\u99ac\u4e58\u5750\u7684\u300c\u7a7a\u8ecd\u4e00\u865f\u300d\u5c08\u6a5f\u665a\u4e0a10\u664242\u5206\u9032\u5165\u4e0a\u6d77\u7a7a\u57df\uff0c\u9810\u8a08\u7d0430\u5206\u9418\u5f8c\u62b5\u9054\u6d66\u6771\u570b\u969b\u6a5f\u5834\uff0c\u958b\u5c55\u4ed6\u4e0a\u4efb\u5f8c\u9996\u6b21\u8a2a\u83ef\u4e4b\u65c5\u3002' 
>>> s.split() 
[u'\u7b80\u8baf\uff1a\u65b0\u83ef\u793e\u5831\u9053\uff0c\u7f8e\u570b\u7e3d\u7d71\u5967\u5df4\u99ac\u4e58\u5750\u7684\u300c\u7a7a\u8ecd\u4e00\u865f\u300d\u5c08\u6a5f\u665a\u4e0a10\u664242\u5206\u9032\u5165\u4e0a\u6d77\u7a7a\u57df\uff0c\u9810\u8a08\u7d0430\u5206\u9418\u5f8c\u62b5\u9054\u6d66\u6771\u570b\u969b\u6a5f\u5834\uff0c\u958b\u5c55\u4ed6\u4e0a\u4efb\u5f8c\u9996\u6b21\u8a2a\u83ef\u4e4b\u65c5\u3002'] 

どのようにすべきと私はこれをしてI18Nを処理するのですか?これはすべての言語で意味がありますか?

私はPython 2.5.4を使用しています。

+0

+1興味深い質問 –

答えて

1

いくつかのネイティブ広東語、北京語、および日本語話者と話した後、それを行うには正しい事は難しいですが、私の現在のアルゴリズムは、まだインターネットの記事の文脈でそれらに理にかなっているようです。

意味、「スペースで分割し、最後に追加する」処理に使用されます。

私はそれを理解していない人々からの苦情を得るまで、怠け者であり続けます。 (2つの文字を保存すると、Unicode文字を使用して... &#x2026代わりに... three dots

私の元の実装への唯一の変更は、それがどの言語でも不要であるため、最後の単語のスペースを強制しないことであろう

+0

HTMLの名前付きエンティティです: '&hellip;'、横書き省略記号。 – ephemient

7

中国語は通常単語間に空白がありません。記号は文脈によって異なる意味を持つことがあります。テキストを単語境界で分割するには、そのテキストを理解する必要があります。つまり、あなたがしようとしていることは、一般的には簡単ではありません。

+0

中国語の文字列を部分文字列にするのは意味がありますか?私が '' [:120] ''と同様に、それはまだ読めるでしょうか? –

+4

半分の単語で終わることがありますが、これは意味を完全に変えることができます。最初の3文字に「アシスト」を分割すると想像してください。 –

+0

よろしくお願いいたします。 "..."は他の言語で同じことを意味するのか、別の "楕円"の文字があるのですか –

5

中国語での単語分割、および自然言語処理におけるその他の高度なタスクについては、完全な解決策ではない場合は、NLTKを良い出発点として考慮してください。豊富なPythonベースのツールキットです。特に、NL処理技術これらの問題のいくつかについてあなたに実行可能な解決策を提供するのにはまれではありません)。

+3

"めったにない" ==普通、時には何か他のもの? –

+0

@Laurenceは、典型的なNLタスクがどのように最先端を行くか、そしてコードが必要な生産を強化し、パフォーマンスを調整する方法によって異なります。テラバイトのテキストを処理している場合や低レイテンシのレスポンスが必要な場合は、スケーラビリティの高い大規模な並列クラスタにデプロイする必要があります.NLTKでは、プロトタイプをスケッチして、必要なソリューションを提供するわけではありません。より少ないボリュームとより多くの時間制限のあるタスク、特にセグメンテーションなどのよく知られているものが「通常」適用されますが、あらゆる種類の中間的なニーズと特殊な問題があります) - –

+2

NLPソリューションをワードブレークディスカバリ用にトレーニングしたくありません。私は誰かがこれを既にやったと確信して、ちょうどpre-boxed wordbreakスプリッタが欲しい。ありがとう。 –

0

これは、改訂された決定をreモジュールに投げつけますが、十分に機能するかもしれません。

import re 

def shorten(tweet, footer="", limit=140): 
    """Break tweet into two pieces at roughly the last word break 
    before limit. 
    """ 
    lower_break_limit = limit/2 
    # limit under which to assume breaking didn't work as expected 

    limit -= len(footer) 

    tweet = re.sub(r"\s+", " ", tweet.strip()) 
    m = re.match(r"^(.{,%d})\b(?:\W|$)" % limit, tweet, re.UNICODE) 
    if not m or m.end(1) < lower_break_limit: 
     # no suitable word break found 
     # cutting at an arbitrary location, 
     # or if len(tweet) < lower_break_limit, this will be true and 
     # returning this still gives the desired result 
     return tweet[:limit] + footer 
    return m.group(1) + footer 
+0

ありがとうございます。単語の境界がない場合はチェックを追加しました。英語の文字列については、これは素晴らしいですが、私の中国語の例では(長めにするために倍にしてください)、140文字ではなく137文字の文字列で終わります。 'len(shorten(s * 2、... end "))' –

+0

これは、最後の\ b \ Wで壊れているので、期待どおりに動作していることを意味します。しかし、私はこれが実際にそのテキスト内の単語区切りであるかどうかを知るために中国語を知らない。それが限界よりも短くなる方法の別の例については 'shorten(" abcde "* 3、" "、13)'を試してください。 –

3

re.U flagは、Unicode文字プロパティデータベースに従って\sを扱います。

>>> x = u'\u7b80\u8baf\uff1a\u65b0\u83ef\u793e\u5831\u9053\uff0c\u7f8e\u570b\u7e3d\u7d71\u5967\u5df4\u99ac\u4e58\u5750\u7684\u300c\u7a7a\u8ecd\u4e00\u865f\u300d\u5c08\u6a5f\u665a\u4e0a10\u664242\u5206\u9032\u5165\u4e0a\u6d77\u7a7a\u57df\uff0c\u9810\u8a08\u7d0430\u5206\u9418\u5f8c\u62b5\u9054\u6d66\u6771\u570b\u969b\u6a5f\u5834\uff0c\u958b\u5c55\u4ed6\u4e0a\u4efb\u5f8c\u9996\u6b21\u8a2a\u83ef\u4e4b\u65c5\u3002' 
>>> re.compile(r'\s+', re.U).split(x) 
[u'\u7b80\u8baf\uff1a\u65b0\u83ef\u793e\u5831\u9053\uff0c\u7f8e\u570b\u7e3d\u7d71\u5967\u5df4\u99ac\u4e58\u5750\u7684\u300c\u7a7a\u8ecd\u4e00\u865f\u300d\u5c08\u6a5f\u665a\u4e0a10\u664242\u5206\u9032\u5165\u4e0a\u6d77\u7a7a\u57df\uff0c\u9810\u8a08\u7d0430\u5206\u9418\u5f8c\u62b5\u9054\u6d66\u6771\u570b\u969b\u6a5f\u5834\uff0c\u958b\u5c55\u4ed6\u4e0a\u4efb\u5f8c\u9996\u6b21\u8a2a\u83ef\u4e4b\u65c5\u3002'] 
+0

右は英語で「空白」を意味しますが、中国語では単語区切りがないため、区切り文字として空白のみが使用されます。 –

-1

保存2つの文字をし、3個のドットの代わりに省略記号(0x2026)を使用します。

与えられた文字列は、しかし、明らかにPythonのUnicodeデータベースに応じて任意の空白文字が含まれていません!

+1

UTF-8では、省略記号は3バイト必要なので、そこに保存することはあまりありません:) –

+2

"バイト"の代わりに "文字"を使用しました。 :) –

+1

Adamの意味:2つのUnicode文字を保存しますが、UTF-8ではU + 2026は3バイト、3つのドットはそれぞれ1バイトとなりますので、保存すると保存されません。私の注意:概念上、省略記号を使用する方が良いです。 –

2

私はプッシュ通知のためのPyAPNSでソリューションを試してみましたが、私にとってうまくいったことを分かち合いたいと思っていました。私が持っていた問題は、UTF-8で256バイトを切り捨てると、通知が破棄されることになります。通知を「unicode_escape」としてエンコードして、動作させる必要がありました。結果はJSONとして送信され、未処理のUTF-8では送信されないため、これを想定しています。とにかく、ここで私のために働いていた機能は次のとおりです。

def unicode_truncate(s, length, encoding='unicode_escape'): 
    encoded = s.encode(encoding)[:length] 
    return encoded.decode(encoding, 'ignore') 
1

は基本的には、(スペースで韓国を除く)CJKでは、あなたが適切にセグメント語に辞書ルックアップを必要とします。単語の正確な定義にもよりますが、語句の変わった変種(つまり「行こう」対「行った」)が辞書に表示されるわけではないため、日本語はそれより難しい場合があります。努力する価値があるかどうかは、アプリケーションによって異なります。

関連する問題