Python: Split unicode string on word boundaries
我需要取一个字符串,并将其缩短为140个字符。
当前我正在做的事情:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | if len(tweet) > 140: tweet = re.sub(r"\\s+","", tweet) #normalize space footer ="a€|" + 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 |
因此,这对英语以及像字符串一样的英语非常有用,但是中文字符串失败,因为
1 2 3 4 5 | >>> s = u"??€è?ˉ????–°è?ˉ?¤??±é?"?????????????μ±?¥§?·′é|??1????????€???oè????€è???€??°??????????10???42???é€2?…¥????μ·??o??????é?è¨??′?30???é???????μé?"?μ|??±???é??????′???é–??±???–?????????é|–???è¨aè?ˉ?1??—…?€?" >>> 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。
中文在单词之间通常没有空格,并且根据上下文,符号可以具有不同的含义。您将必须理解文本才能在单词边界处进行拆分。换句话说,您通常想做的事情并不容易。
对于中文分词以及处理自然语言的其他高级任务,如果不是完整的解决方案,则可以将NLTK视为一个很好的起点-这是一个基于Python的丰富工具包,特别适合于学习NL处理技术(和往往不够好,无法为您解决其中一些问题)。
根据python的unicode数据库,给定的字符串显然不包含任何空格字符: 我尝试使用PyAPNS的推送通知解决方案,只是想分享对我有用的解决方案。我遇到的问题是,在UTF-8中以256个字节截断会导致删除通知。我必须确保将通知编码为" unicode_escape "才能使其正常工作。我假设这是因为结果以JSON而非原始UTF-8的形式发送。无论如何,这里是对我有用的功能: 基本上,在CJK(带空格的韩语除外)中,您需要字典查找才能正确分割单词。根据您对"单词"的确切定义,日语可能会比这更困难,因为并非所有单词的变体形式(即"è????" ??? "与"è?? ?? £ ??? ")将出现在字典中。是否值得付出努力取决于您的应用程序。 在与一些以粤语,普通话和日语为母语的人交谈之后,看来正确的事情很难,但是在互联网帖子的背景下,我目前的算法仍然对他们有意义。 意思是,它们习惯于"在空间上分割并在末尾添加a ||"。 所以我要懒惰并坚持下去,直到我收到了一些不了解它的人的抱怨。 对我原来的实现的唯一更改是不要在最后一个单词上加上空格,因为在任何语言中都不需要它(并使用unicode字符a €| 您正在寻找的是中文分词工具。分词不是一件容易的事,目前还不能很好地解决。有几种工具: CkipTagger 由台湾中央研究院开发。 jieba 由Sun开发百度工程师Junyi。
2
3
>>> 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']
2
3
encoded = s.encode(encoding)[:length]
return encoded.decode(encoding, 'ignore')
pkuseg
北京大学语言计算和机器学习小组开发的
如果您要的是字符分割,尽管不是很有用,但可以做到。
1 2 3 4 5 6 | >>> s = u"??€è?ˉ????–°è?ˉ?¤??±é?"?????????????μ±?¥§?·′é|??1????????€???oè????€è???€??°??????????10???42???é€2?…¥????μ·??o??????é?è¨??′?30???é???????μé?"?μ|??±???é??????′???é–??±???–?????????é|–???è¨aè?ˉ?1??—…?€?" >>> chars = list(s) >>> chars [u'\\u7b80', u'\\u8baf', u'\\uff1a', u'\\u65b0', u'\\u83ef', u'\\u793e', u'\\u5831', u'\\u9053', u'\\uff0c', u'\\u7f8e', u'\\u570b', u'\\u7e3d', u'\\u7d71', u'\\u5967', u'\\u5df4', u'\\u99ac', u'\\u4e58', u'\\u5750', u'\\u7684', u'\\u300c', u'\\u7a7a', u'\\u8ecd', u'\\u4e00', u'\\u865f', u'\\u300d', u'\\u5c08', u'\\u6a5f', u'\\u665a', u'\\u4e0a', u'1', u'0', u'\\u6642', u'4', u'2', u'\\u5206', u'\\u9032', u'\\u5165', u'\\u4e0a', u'\\u6d77', u'\\u7a7a', u'\\u57df', u'\\uff0c', u'\\u9810', u'\\u8a08', u'\\u7d04', u'3', u'0', u'\\u5206', u'\\u9418', u'\\u5f8c', u'\\u62b5', u'\\u9054', u'\\u6d66', u'\\u6771', u'\\u570b', u'\\u969b', u'\\u6a5f', u'\\u5834', u'\\uff0c', u'\\u958b', u'\\u5c55', u'\\u4ed6', u'\\u4e0a', u'\\u4efb', u'\\u5f8c', u'\\u9996', u'\\u6b21', u'\\u8a2a', u'\\u83ef', u'\\u4e4b', u'\\u65c5', u'\\u3002'] >>> print('/'.join(chars)) ??€/è?ˉ/???/?–°/è?ˉ/?¤?/?±/é?"/???/???/???/???/?μ±/?¥§/?·′/é|?/?1?/???/???/?€?/??o/è??/??€/è??/?€?/?°?/???/???/???/1/0/???/4/2/???/é€2/?…¥/???/?μ·/??o/???/???/é?/è¨?/?′?/3/0/???/é??/???/??μ/é?"/?μ|/??±/???/é??/???/?′/???/é–?/?±?/??–/???/???/???/é|–/???/è¨a/è?ˉ/?1?/?—…/?€? |
这会把断字的决定推到re模块上,但它可能对您来说足够好。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 |
保存两个字符并使用省略号(