String」タグアーカイブ

PythonのString Formattingを拡張

Python 3で追加されたformatを使うと文字列操作が便利になります。

使い方は次のような感じです。(参考:Pythonの新しい文字列書式操作

>>> '{0} + {1} = {2}'.format(1, 2, 1+2)
'1 + 2 = 3'

string.Formatterを継承すると、この文字列操作を拡張することができるそうです。

拡張の仕方は以下のような感じです。

class Formatter(string.Formatter):
  def format_field(self, value, spec):
    # 必要な処理
    return 'value'

サンプル

このstring.Formatterを継承してupperlowerを書式指定文字列に使うと大文字・小文字に変換するサンプルを作ってみました。

import string
class Formatter(string.Formatter):
  def format_field(self, value, spec):
    if spec == 'upper': value, spec = value.upper(), ''
    elif spec == 'lower': value, spec = value.lower(), ''
    return super(Formatter, self).format_field(value, spec)

使い方は以下のような感じです。

>>> f = Formatter()
>>> f.format('{name} {name:upper} {name:lower}', name='Alice')
'Alice ALICE alice'

template engine

このString Formattingを使ってtemplate engineのようなことを実装したサンプルのようなものも公開されているみたいです。

GitHub – ebrehault/superformatter
https://github.com/ebrehault/superformatter

repeatcallifに対応していて、次のような感じで使えます。

>>> from engine import SuperFormatter
>>> sf = SuperFormatter()
>>> print(sf.format('{n:repeat:n={{item}}\n}', n=[2,3,5,7]))
n=2
n=3
n=5
n=7

現状ではサンプル程度のものかと思いますが、面白そうなテクニックかなと思います。

リンク

string — Common string operations — Python 3.7.2 documentation
https://docs.python.org/3/library/string.html

The world’s simplest Python template engine — Makina Corpus
https://makina-corpus.com/blog/metier/2016/the-worlds-simplest-python-template-engine

PythonでUnicodeのオブジェクトとコードポイントの変換

UnicodeオブジェクトをUnicodeコードポイントに変換

>>> ord(u'あ')
12354

UnicodeコードポイントをUnicodeオブジェクトに変換

>>> unichr(12354)
u'\u3042'
>>> print unichr(12354)
あ

8ビット文字列にordを使うとASCIIコードを取得することもできます。

>>> ord('a')
97
>>> chr(97)
'a'
>>> unichr(97)
u'a'

Pythonで全角を2文字として文字数を数える方法

Pythonの文字列はlen関数で文字数をカウントできますが、全角と半角の区別はしません。

>>> len(u'abcde')
5
>>> len(u'あいうえお')
5

これはこれで便利な実装なのですが、日本語のテキスト処理をしていると、等幅フォントを使ったときに幅をそろえたいなどで、全角を2文字として数えると何文字になるか調べたいことがあります。そういう場合にはunicodedataeast_asian_widthが使えるようです。

unicodedata.east_asian_width(chr)
ユニコード文字 chr に割り当てられたeast asian widthを文字列で返します。
http://docs.python.jp/3.3/library/unicodedata.html

east_asian_widthの戻り値はF H W Na A Nで、それぞれ次のような意味になっているようです。

F(Fullwidth; 全角)- 互換分解特性 を持つ互換文字。文字の名前に “FULLWIDTH” を含む。いわゆる全角英数など。
H(Halfwidth; 半角)- 互換分解特性 を持つ互換文字。文字の名前に “HALFWIDTH” を含む。いわゆる半角カナなど。
W(Wide; 広)- 上記以外の文字で、従来文字コードではいわゆる全角であったもの。漢字や仮名文字、東アジアの組版にしか使われない記述記号(たとえば句読点)など。
Na(Narrow; 狭)- 上記以外の文字で、従来文字コードでは対応するいわゆる全角の文字が存在したもの。いわゆる半角英数など。
A(Ambiguous; 曖昧)- 文脈によって文字幅が異なる文字。東アジアの組版とそれ以外の組版の両方に出現し、東アジアの従来文字コードではいわゆる全角として扱われることがある。ギリシア文字やキリル文字など。
N(Neutral; 中立)- 上記のいずれにも属さない文字。東アジアの組版には通常出現せず、全角でも半角でもない。アラビア文字など。

http://ja.wikipedia.org/wiki/%E6%9D%B1%E3%82%A2%E3%82%B8%E3%82%A2%E3%81%AE%E6%96%87%E5%AD%97%E5%B9%85

実際に使ってみると次のようになります。

>>> from unicodedata import east_asian_width
>>> east_asian_width(u'1')
F
>>> east_asian_width(u'ア')
H
>>> east_asian_width(u'あ')
W
>>> east_asian_width(u'a')
Na
>>> east_asian_width(u'α')
A

これを使って、全角を2文字として文字数をカウントするには、例えば次のようにできます。

>>> def length(s):
...   len = 0
...   for i in s:
...     if 'NaH'.count(east_asian_width(i)) > 0:
...       len += 1
...     else:
...       len += 2
...
>>> length(u'hello, 世界!')
12