How to make datas our friends

「エンジニアは発信していくことが責務である」という言葉に感化されて始めた勉強したことを書き留めていく備忘録的なやつ。

Pythonで文章をTypoglycemia化する

背景

言語処理100本ノック 2015を今やっているのでその備忘録的なやつ。

やりたいこと

スペースで区切られた単語列に対して、各単語の先頭と末尾の文字は残しそれ以外の文字の順序をランダムに並び替えるプログラムを作成する。
ただし、長さが4以下の単語は並び替えないこと。

適当な英語の文(例えば"I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind .")を与え、その実行結果を確認する。

結果

単語の文字列をランダムに並び替える関数と、それを使用して文章をTypoglycemia化する関数の2つを用意しました。
なにかしらの関数で同じことができるかなと思ったのですが、すぐに見つからなかった&面白そうなので一から関数を用意して挑戦してみました。

▼ 単語の文字列をランダムに並び替える関数

import random
import re

def radomizeWord(word):
    # 変数を用意
    charList = []
    newList = []
    result = ''

    # 単語を分割してリスト化
    for i in range(0, len(word)):
        charList.insert(i, word[i])

    cnt = len(charList)-1
    
    # 末尾の文字を新リストの末端に挿入し旧リストから削除
    newList.insert(cnt, charList[cnt])
    charList.pop()
    # 先頭の文字を新リストの先頭に挿入し旧リストから削除
    newList.insert(0, charList[0])
    charList.pop(0)

    # 先頭と末尾の単語以外をランダムに抽出して新リストのii番目に挿入
    for ii in range (0, len(charList)):
        num = random.randrange(0, len(charList))
        newList.insert(ii+1, charList[num])
        # 挿入した文字は旧リストから削除
        charList.pop(num)

    for iii in range(0, len(newList)):
        result += newList[iii]

    return result

▼ 上の関数を使用して文章をTypoglycemia化する関数

def generateTypoglycemia(sentense):
    # 文章を単語に分割
    wordsList = re.split('\s', sentense)
    # 変数を用意
    resultList = []
    result = ''
    
    for i in range (0, len(wordsList)) :
        if len(wordsList[i]) <= 4:
            resultList.insert(i, wordsList[i])
        elif len(wordsList[i]) > 4:
            resultList.insert(i, radomizeWord(wordsList[i]))
            
    for ii in range (0, len(resultList)) :
        if ii == 0 :
            result += resultList[ii]
        elif ii != 0 :
            result += (' ' + resultList[ii])
    
    return result


▼ 実行結果

> generateTypoglycemia("I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind.")
> "I c'dnlout blveeie that I cuold alalutcy unrndetsad what I was rainedg : the pheonnamel pwoer of the huamn mdin."

解説/考察

単語の頭と末尾をそのままに間の文字を入れ替えても読めるぞおおお!というのがタイポグリセミアらしいです。
Typoglycemiaとは (タイポグリセミアとは) [単語記事] - ニコニコ大百科

ちょっと長いだけで特別難しいことはやっていないです。

単語を頭とケツの二文字以外ランダムに入れ替える方法ですが、今回は文字をばらして最初の文字をリストの頭に最後の文字をリストのケツに入れてから間の文字をランダムに抽出してリストに順番に入れていく方法で対応しました。

▼単語を文字単位で分割して順番にリストに格納

for i in range(0, 文字列の文字数):
 文字リスト.insert(i, 文字列[i])

▼文字列の頭とケツの文字を新しいリストの頭とケツにINSERTして削除。

「文字列の文字数-1」をやっているのはリストが0から始まるので、len()関数で取得した数字から1引いてあげる必要があるため。

新文字リスト.insert(文字列の文字数-1, 文字リスト[文字列の文字数-1])
文字リスト.pop()
新文字リスト.insert(0, 文字リスト[0])
文字リスト.pop(0)

文字リスト内の残りの文字を、文字リストに収められている文字数分for文を回してランダムに抽出して新文字リストに挿入しています。
挿入が終わったら最後にリストから除外。

for ii in range (0, len(文字リスト)):
 num = random.randrange(0, len(文字リスト))
 新文字リスト.insert(ii+1,文字リスト[num])
 文字リスト.pop(num)

あとは文章を単語に分割して、単語の文字数が4以上の場合この関数を使用して文字を入れ替える、というのをやっています。

心残りは、文章の最後にコンマが来た場合文字として認識してしまう件ですw
たとえば今回の例だと最後の単語が「mind.」であるため四文字以上と判定されランダムに文字を入れ替えてしまうので時間があるときに直したいです。