半角英数字だけでなく、記号文字、!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ を含め
ASCII コード文字を対応する全角文字への変換、または逆(ASCIIコードへの変換)を
正規表現ではなく、計算で行う処理を Pytnon で書いてみました。
2通りの方法が考えられます。
・join の方法:変換対象文字列を Iteratable としてリスト内包表記で計算して join する方法
・redudeの方法:変換対象文字列を Iteratable として reduce のラムダでまとめる方法
テストの前準備
ASCIIコードを chr() で求める
>>> from functools import reduce >>> reduce(lambda r,t:r+chr(t),range(32, 127), '') ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
全角スペースを覗いたASCIIコードの全角文字を chr() で求める
>>> from functools import reduce >>> reduce(lambda r,t:r+chr(t),range(65281, 65375), '') '!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
これを元に、
s = ASCIIコード
s = reduce(lambda r,t:r+chr(t),range(32, 127), '')
z = 全角スペース+ASCIIコードの全角文字
z = ' ' + reduce(lambda r,t:r+chr(t),range(65281, 65375), '')
以下、其々の方法のメソッド
join の方法、(半角→全角)
def asciiToZenByJoin(target): return ''.join([chr(n+65248) if 32 < n and n < 127 else chr(12288) if n==32 else chr(n) for n in [ord(c) for c in target]])
reduce の方法、(半角→全角)
def asciiToZenByReduce(target): return reduce(lambda r,t:r+(chr(t+65248) if 32 < t and t < 127 else chr(12288) if t==32 else chr(t)), [ord(c) for c in target], '')
join の方法、(全角→半角)
def zenToASCIIByJoin(target): return ''.join([chr(n-65248) if 65280 < n and n < 65375 else chr(32) if n==12288 else chr(n) for n in [ord(c) for c in target]])
reduce の方法、(全角→半角)
def zenToASCIIByReduce(target): return reduce(lambda r,t:r+(chr(t-65248) if 65280 < t and t < 65375 else chr(32) if t==12288 else chr(t)), [ord(c) for c in target], '')
計測の処理:1万回の実行で計測
print( asciiToZenByJoin(s) ) t = timeit('asciiToZenByJoin(s)', globals=globals(), number=10000) print('join の方法、(半角→全角): {}'.format(t)) print( asciiToZenByReduce(s) ) t = timeit('asciiToZenByReduce(s)', globals=globals(), number=10000) print('reduce の方法、(半角→全角): {}'.format(t)) print( zenToASCIIByJoin(z) ) t = timeit('zenToASCIIByJoin(s)', globals=globals(), number=10000) print('join の方法、(全角→半角): {}'.format(t)) print( zenToASCIIByReduce(z) ) t = timeit('zenToASCIIByReduce(s)', globals=globals(), number=10000) print('reduce の方法、(全角→半角): {}'.format(t))
結果
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ join の方法、(半角→全角): 0.39903364785408185 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ reduce の方法、(半角→全角): 0.532446630128369 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ join の方法、(全角→半角): 0.28868796883428294 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ reduce の方法、(全角→半角): 0.41078418085099
計測値は、実行環境によって差がありますが、
・join の方法:変換対象文字列を Iteratable としてリスト内包表記で計算して join する方法
が速いという結果です。
直感的な見た目で reduce の記述の方がロジックとして読みやすく速いのではないかと
錯覚するのは、Java を多く書いていた感覚なのかもしれません。
すぐに、reduce は遅いと決めつけるのは良くないと思いますが。。。
いろいろやってみるべきと思っています。