5
1

More than 3 years have passed since last update.

横書きの文章を縦書きに変換してTwitterなどに投稿したい

Posted at

Twitterなど、ほぼ全てのSNSは横書きですね。Pythonプログラミングの勉強も兼ねて、これを縦書きに変換するPythonスクリプトを書いてみましょう。

Tweet

以下のツイートを縦書きにしてみたいと思います。

tweet = '''\
普通は Tweet は横書きなんだけどさ、
これを縦書きにしたいわけよ。
そうすると、検索されにくくなるんじゃね?
いっちょ Pythonでやってみないか?
'''
tweet
'普通は Tweet は横書きなんだけどさ、\nこれを縦書きにしたいわけよ。\nそうすると、検索されにくくなるんじゃね?\nいっちょ Pythonでやってみないか?\n'

1文字1文字に分解

次のようにすれば1文字1文字に分解できます。

for line in tweet.split("\n"):
    print([line[i] for i in range(len(line))])
['普', '通', 'は', ' ', 'T', 'w', 'e', 'e', 't', ' ', 'は', '横', '書', 'き', 'な', 'ん', 'だ', 'け', 'ど', 'さ', '、']
['こ', 'れ', 'を', '縦', '書', 'き', 'に', 'し', 'た', 'い', 'わ', 'け', 'よ', '。']
['そ', 'う', 'す', 'る', 'と', '、', '検', '索', 'さ', 'れ', 'に', 'く', 'く', 'な', 'る', 'ん', 'じ', 'ゃ', 'ね', '?']
['い', 'っ', 'ち', 'ょ', ' ', 'P', 'y', 't', 'h', 'o', 'n', 'で', 'や', 'っ', 'て', 'み', 'な', 'い', 'か', '?']
[]

ただし、最後の行だけ空白行になってしまうので除外しましょう。

for line in tweet.split("\n"):
    if len(line) > 0:
        print([line[i] for i in range(len(line))])
['普', '通', 'は', ' ', 'T', 'w', 'e', 'e', 't', ' ', 'は', '横', '書', 'き', 'な', 'ん', 'だ', 'け', 'ど', 'さ', '、']
['こ', 'れ', 'を', '縦', '書', 'き', 'に', 'し', 'た', 'い', 'わ', 'け', 'よ', '。']
['そ', 'う', 'す', 'る', 'と', '、', '検', '索', 'さ', 'れ', 'に', 'く', 'く', 'な', 'る', 'ん', 'じ', 'ゃ', 'ね', '?']
['い', 'っ', 'ち', 'ょ', ' ', 'P', 'y', 't', 'h', 'o', 'n', 'で', 'や', 'っ', 'て', 'み', 'な', 'い', 'か', '?']

以上の処理を、リスト内包表記を使ってスマートに表現し、 data という変数に入れます。

data = [[line[i] for i in range(len(line))] for line in tweet.split("\n") if len(line) > 0]
print(data)
[['普', '通', 'は', ' ', 'T', 'w', 'e', 'e', 't', ' ', 'は', '横', '書', 'き', 'な', 'ん', 'だ', 'け', 'ど', 'さ', '、'], ['こ', 'れ', 'を', '縦', '書', 'き', 'に', 'し', 'た', 'い', 'わ', 'け', 'よ', '。'], ['そ', 'う', 'す', 'る', 'と', '、', '検', '索', 'さ', 'れ', 'に', 'く', 'く', 'な', 'る', 'ん', 'じ', 'ゃ', 'ね', '?'], ['い', 'っ', 'ち', 'ょ', ' ', 'P', 'y', 't', 'h', 'o', 'n', 'で', 'や', 'っ', 'て', 'み', 'な', 'い', 'か', '?']]

numpy で転置

行列の転置したいので numpy が使えるといいのですが

import numpy as np
np.array(data)
array([list(['普', '通', 'は', ' ', 'T', 'w', 'e', 'e', 't', ' ', 'は', '横', '書', 'き', 'な', 'ん', 'だ', 'け', 'ど', 'さ', '、']),
       list(['こ', 'れ', 'を', '縦', '書', 'き', 'に', 'し', 'た', 'い', 'わ', 'け', 'よ', '。']),
       list(['そ', 'う', 'す', 'る', 'と', '、', '検', '索', 'さ', 'れ', 'に', 'く', 'く', 'な', 'る', 'ん', 'じ', 'ゃ', 'ね', '?']),
       list(['い', 'っ', 'ち', 'ょ', ' ', 'P', 'y', 't', 'h', 'o', 'n', 'で', 'や', 'っ', 'て', 'み', 'な', 'い', 'か', '?'])],
      dtype=object)

以上のように、リストのアレイになってしまい、うまくいきません。

そこで、行数と列数をしっかり測って、その大きさに相当する配列を用意しましょう。

max_length = 0 # 最も長い文の文字数を数える
for d in data:
    if max_length < len(d):
        max_length = len(d)

以上のようにすれば、 tweetlen(data)max_length 列の配列で表現できることが分かります。そこで、同じ大きさの numpy 配列を用意しましょう。あらかじめ空白文字で埋めておきます。

import numpy as np
np.full((len(data), max_length), " ")
array([['\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000', '\u3000', '\u3000'],
       ['\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000', '\u3000', '\u3000'],
       ['\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000', '\u3000', '\u3000'],
       ['\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000', '\u3000', '\u3000']], dtype='<U1')

あとは、その numpy array に data の文字を1文字1文字書き写します。

ただし、このとき、文の順序が逆になるようにします。

data2 = np.full((len(data), max_length), " ")
for i in range(len(data)):
    for j in range(max_length):
        if j < len(data[i]):
            data2[len(data) - i - 1][j] = data[i][j]
data2
array([['い', 'っ', 'ち', 'ょ', ' ', 'P', 'y', 't', 'h', 'o', 'n', 'で', 'や',
        'っ', 'て', 'み', 'な', 'い', 'か', '?', '\u3000'],
       ['そ', 'う', 'す', 'る', 'と', '、', '検', '索', 'さ', 'れ', 'に', 'く', 'く',
        'な', 'る', 'ん', 'じ', 'ゃ', 'ね', '?', '\u3000'],
       ['こ', 'れ', 'を', '縦', '書', 'き', 'に', 'し', 'た', 'い', 'わ', 'け', 'よ',
        '。', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000', '\u3000',
        '\u3000'],
       ['普', '通', 'は', ' ', 'T', 'w', 'e', 'e', 't', ' ', 'は', '横', '書',
        'き', 'な', 'ん', 'だ', 'け', 'ど', 'さ', '、']], dtype='<U1')

ここまでできれば、行列の転置を用いて縦書きにできます。

data2.T # 行列の転置
array([['い', 'そ', 'こ', '普'],
       ['っ', 'う', 'れ', '通'],
       ['ち', 'す', 'を', 'は'],
       ['ょ', 'る', '縦', ' '],
       [' ', 'と', '書', 'T'],
       ['P', '、', 'き', 'w'],
       ['y', '検', 'に', 'e'],
       ['t', '索', 'し', 'e'],
       ['h', 'さ', 'た', 't'],
       ['o', 'れ', 'い', ' '],
       ['n', 'に', 'わ', 'は'],
       ['で', 'く', 'け', '横'],
       ['や', 'く', 'よ', '書'],
       ['っ', 'な', '。', 'き'],
       ['て', 'る', '\u3000', 'な'],
       ['み', 'ん', '\u3000', 'ん'],
       ['な', 'じ', '\u3000', 'だ'],
       ['い', 'ゃ', '\u3000', 'け'],
       ['か', 'ね', '\u3000', 'ど'],
       ['?', '?', '\u3000', 'さ'],
       ['\u3000', '\u3000', '\u3000', '、']], dtype='<U1')

転置した行列を文字列として出力

delimiter = " "
for line in data2.T:
    print(delimiter.join(line))
い そ こ 普
っ う れ 通
ち す を は
ょ る 縦  
  と 書 T
P 、 き w
y 検 に e
t 索 し e
h さ た t
o れ い  
n に わ は
で く け 横
や く よ 書
っ な 。 き
て る   な
み ん   ん
な じ   だ
い ゃ   け
か ね   ど
? ?   さ
      、

これを、リスト内包表記を使ってスマートに書き直せばこうなります。

delimiter = " "
print("\n".join([delimiter.join(line) for line in data2.T]))
い そ こ 普
っ う れ 通
ち す を は
ょ る 縦  
  と 書 T
P 、 き w
y 検 に e
t 索 し e
h さ た t
o れ い  
n に わ は
で く け 横
や く よ 書
っ な 。 き
て る   な
み ん   ん
な じ   だ
い ゃ   け
か ね   ど
? ?   さ
      、

まとめ

以上の操作を yoko2tate という関数にしてみました。

def yoko2tate(tweet, delimiter = " "):
    data = [[line[i] for i in range(len(line))] for line in tweet.split("\n") if len(line) > 0]
    max_length = 0
    for d in data:
        if max_length < len(d):
            max_length = len(d)
    data2 = np.full((len(data), max_length), " ")
    for i in range(len(data)):
        for j in range(max_length):
            if j < len(data[i]):
                data2[len(data) - i - 1][j] = data[i][j]
    return "\n".join([delimiter.join(line) for line in data2.T])

使用例はこんな感じ。

tweet = '''\
あ...ありのまま 今 起こったことを話すぜ!

「ツイートを入力したら、縦書きになった」

な...何を言っているか分からねーと思うが、おれも何をされたのか分からなかった...
'''

print(yoko2tate(tweet))
な 「 あ
. ツ .
. イ .
. ー .
何 ト あ
を を り
言 入 の
っ 力 ま
て し ま
い た  
る ら 今
か 、  
分 縦 起
か 書 こ
ら き っ
ね に た
ー な こ
と っ と
思 た を
う 」 話
が   す
、   ぜ
お   !
れ    
も    
何    
を    
さ    
れ    
た    
の    
か    
分    
か    
ら    
な    
か    
っ    
た    
.    
.    
.    
5
1
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1