Python基礎3: 文字列操作
概要
機械学習を実行する前に所定のファイル(例:Excel, CSV)からデータを集めることがありますが、データが下記の状態だと使用できません。参考までに総務省より「統計表における機械判読可能なデータ作成に関する表記方法」のように入力するのが最適です。
上記の状態だと数値として使用できなかったりファイルにアクセスできないため、文字列操作をして使える形にしていきます。もちろん文字列操作は上記理由だけでなく必要な情報を抽出するためにも使用します。
1.基礎操作:抽出(スライス)・計算
文字列は初学者ではイメージできないくらい色々な操作ができます。イテラブル出るため下記のようなことができます。
[In]
text = '通常は製造業で環境系の設計をしています。'
print(text[0], text[3], text[4]) #文字をテキストのインデックスから抽出
print(text[:5]) #スライス機能
text2 = '今日は' + 'とても'*2 + '楽しかった' #足し算と掛け算※見にくいため通常はしっかり記載します。
print(text2)
[Out]
通 製 造
通常は製造
今日はとてもとても楽しかった
2.書式化
2-1.記法の紹介:f-string/format
文字列内に指定値や変数を穴埋めする時に書式化を使用します。書式化は大きく分けて3つあります。
[In]
text = '9月24日の日経平均株価は30248.8円です。'
today, stockprice = '9月24日', '30248.81'
#すべて同じ結果を出力
print(f'{today}の日経平均株価は{stockprice}円です。') #f-string
print('{}の日経平均株価は{}円です。'.format(today, stockprice)) #format
print('%sの日経平均株価は%s円です。'%(today, stockprice)) #%演算子
[Out]※すべて同じ結果のため一つのみ表示
9月24日の日経平均株価は30248.81円です。
【補足:f-stringのエスケープシーケンス】
f-stringsのエスケープシーケンスは\ではなく{}でできます。
[In]
text = '9月24日の日経平均株価は30248.8円です。'
today, stockprice = '9月24日', '30248.81'
print(f'{today}の日経平均株価は{{stockprice}}円です。') #f-string
[Out]
9月24日の日経平均株価は{stockprice}円です。
2-2.書式の指定
書式化した値の書式を指定する場合は{変数:<指定>}とします。
[IN]
stockprice = 30248.81 #数値 (小数点)を指定
print(f'通常:{stockprice}')
print(f'f指定:{stockprice:1f}, {stockprice:3f}')
print(f'd指定:{int(stockprice):d}') #Floatタイプにはエラー
print(f'e指定:{stockprice:e}')
[OUT]
通常:30248.81
f指定:30248.810000, 30248.810000
d指定:30248
e指定:3.024881e+04
2-3.x桁数の数値(0パディング):zfill()
x桁の数値を作成したい場合は<文字列数値※intはエラー>.zfill("桁数")で指定します。
[IN]
num = '2' #文字列型の数値
print(num.zfill(2))
print(num.zfill(4))
for i in range(3):
print(f'{str(i).zfill(3)}番')
[OUT]
02
0002
000番
001番
002番
なお直接フォーマット指定する方法もあります。
[IN]
for i in range(3):
print(f'{i:03d}番')
[OUT]
000番
001番
002番
3.分離/結合
3-1.分割:text.split()
分割はsplit(<対象文字>)でリストを出力します。何も指定しない場合(デフォルト値)はスペースとなります。
分割後の文字列にスライス機能を使うと指定文字列を抽出できます。
[In]
text = '9月24日の日経平均株価は30248.8円です。'
print(text.split('株価'))
print(text.split('円')[0][-7:]) #日付の桁数が変化しても金額の桁数が変わらなければ安定して値を取得できる。
[Out]
['9月24日の日経平均', 'は30248.8円です。']
30248.8
[IN]
text = '9月24 日の日 経平均 株価は3 02 48.8円です。'
print(text.split()) #デフォルトでは空白で区切る
[OUT]
['9月24', '日の日', '経平均', '株価は3', '02', '48.8円です。']
3-2.結合:text.join()
結合は "間に入れる文字".join(対象)とします。対象はイテラブルのため文字列だけでなくリストなども使用可能です。空文字""でjoinするとすべてが結合されたテキストが作成されます。
[In]
text_1= 'テストの文字列'
print('_'.join(text_1))
textlist = ['AI', 'DL', 'NN', 'CNN']
print('、'.join(textlist))
print(''.join(textlist))
[Out]
テ_ス_ト_の_文_字_列
AI、DL、NN、CNN
AIDLNNCNN
4.置換
4-1.文字列の置換:text.replace()
文字列を置換したい場合はreplace('置換前','置換後')を使用します。
[In]
text = '9月24日の日経平均株価は30248.81円です。'
print(text.replace('9月24日', '9月22日')) #文字列を直接入力
yesterday, stockprice_ys = '9月22日', '29639.4'
print(text.replace(today, yesterday).replace(stockprice, stockprice_ys)) #変数も可。replaceを重ねると重複処理できる。
[Out]
9月22日の日経平均株価は30248.81円です。
9月22日の日経平均株価は29639.4円です。
4-2.書式化を利用:%s
前述した書式化を使用して置換も可能です。文字列の置換したい箇所に"%s"を埋め込み"<出力する文字> % <置換したい文字>"とすることで文字列の置換が可能です。
[IN]
text = '9月24日の日経平均株価は%sです。'
print(text % '30248.81円')
[OUT]
9月24日の日経平均株価は30248.81円です。
[IN ※for文でも対応可能]
text = '9月24日の日経平均株価は%sです。'
for i in range(1, 4):
print(text % f'{i*10000}円です')
[OUT]
9月24日の日経平均株価は10000円ですです。
9月24日の日経平均株価は20000円ですです。
9月24日の日経平均株価は30000円ですです。
5.検索・確認
5-1.Index検索(index, find)
文字列の中に指定した文字が存在するか、存在する場合のインデックス番号はいくつかを確認する方法は下記のとおりです。
[In]
text = '9月24日の日経平均株価は30248.8円です。'
print(text.index('日')) #最初の24日の方を取得
print(text.index('日経')) #24日の日は無視して日経の日を取得
print(text.find('日')) #findはindexと同じだが、見つからなかった場合は-1を返す。
print(text.find('ダウ')) #indexだとエラー:ValueError: substring not found
[Out]
4
6
4
-1
5-2.文字列の存在確認
指定文章内に特定の文字列が含まれるかの確認は<指定文字>in textとなります。
[IN]
text = '9月24日の日経平均株価は30248.8円です。'
print('日経' in text) #存在しているか
print('NYダウ' not in text) #存在していないか
[OUT]
True
True
6.表記ゆれの修正
緒言に記載のとおり文字列が正確にそろっていない(表記ゆれ)とパソコンは同じものと判断できません。
(例:「為替レート」という文字列からif文を使用して為替を取得するときに、文字列が「為替レート」だとif文はFalseと判断するため値が取れない。)
本章では表記ゆれの修正方法を記載します。
6ー1.大文字・小文字変換
大文字⇔小文字変換の処理は下記のとおりです。
[In]
import string
words = string.ascii_lowercase #'abcdefghijklmnopqrstuvwxyz'
uppercases = words.upper() #大文字に変換 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
print(uppercases)
lowercases = uppercases.lower() #小文字に変換 'abcdefghijklmnopqrstuvwxyz'
print(lowercases)
print(lowercases.capitalize()) # 最初の文字だけ大文字に変換
[Out]
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
Abcdefghijklmnopqrstuvwxyz
6-2.空白除去:text.strip()/rstrip・lstrip
テキスト前後の空白除去はtext.strip()で処理します。
[In]
text_space = ' 頭とお尻にスペースを入れてます '
print(text_space)
print(text_space.strip()) #空白除去
[Out]
頭とお尻にスペースを入れてます
頭とお尻にスペースを入れてます
片側だけ空白を除去する場合はrstrip()やlstrip()を使用します。
[IN]
text_space = ' 頭とお尻にスペースを入れてます '
print(text_space,'end')
print(text_space.rstrip(),'end') #空白除去
print(text_space.lstrip(),'end') #空白除去
[OUT]
頭とお尻にスペースを入れてます end
頭とお尻にスペースを入れてます end
頭とお尻にスペースを入れてます end
6-3.正規化:unicodedata(標準ライブラリ)
表記ゆれの処理としてunicodedataライブラリを紹介します。unicodedata.normalize(正規化方法, 処理する文字列 )とすることで、表記ゆれを直してくれます。正規化方法は'NFC'、'NFKC'、'NFD'、'NFKD'の4つですが'NFKD'が一般的です。(正規化が何をしてくれるかは下記参照)
[In]
import unicodedata
text = '9ガツ24にちのニッケイヘイキンカブカは30248.81円です。'
print(unicodedata.normalize("NFKC", text))
[Out]
9ガツ24にちのニッケイヘイキンカブカは30248.81円です。
6-4.参考:表記ゆれの例
地獄だった表記ゆれの例として「おねだりを覚えて見つめてくるコツメカワウソ」という文字列を紹介します。どう見ても見た目は同じだと思うのですが"だ"の周辺で差異がでており別物として扱われています。
unicodedataで正規化することで差をなくしました。
[IN]
prompt1 = 'おねだりを覚えて見つめてくるコツメカワウソ'
prompt2 = 'おねだりを覚えて見つめてくるコツメカワウソ'
print(prompt1==prompt2)
print(str(prompt1)==str(prompt2))
print(prompt1[:2]+prompt1[3:] , prompt2[:2]+prompt2[3:])
print(prompt1[2:5],prompt2[2:5])
print(prompt1[3:5],prompt2[3:5])
import unicodedata
unicodedata.normalize('NFC', prompt1) == unicodedata.normalize('NFC', prompt2)
[OUT]
False
False
おねりを覚えて見つめてくるコツメカワウソ おね゙りを覚えて見つめてくるコツメカワウソ
だりを だり
りを ゙り
True
7.文字列用ライブラリ
7-1.正規表現(re)
文字列を指定の条件で抽出できる処理です。覚えるのはかなり大変ですが、理解できると文字列から指定の情報だけきれいに抽出できます。
pythonではreライブラリで使用可能です。
詳細は別途下記記事に記載しております。
[In]
import re
text = '9月24日の日経平均株価は30248.8円です。'
print(re.findall('.月..日',text)) #.は任意の一文字を意味します。この記載だと2桁月や一桁日は取れません
print(re.findall('\d',text)) #\dは数字
print(re.findall('\d{5}',text)) #\dは数字であり{回数}を指定すると指定した連数を取得
print('*'*50) #ただ線を引くだけ:文字列の掛け算
print(re.findall('[^日]+日', text)) #日が現れる直前までの数字・文字列=>24日と日経があるため2つのリストになる。
date_text = re.match('[^日]+日', text)
print(date_text) #matchメソッドだと対象文字列の先頭のみ:indexも返す。
print(f'group():{date_text.group()}、span():{date_text.span()}、start():{date_text.start()}、end():{date_text.end()}') #matchメソッドの値を取得
print(re.findall('[^円]+円', text)) #円が現れる直前までの数字・文字列
[Out]
['9月24日']
['9', '2', '4', '3', '0', '2', '4', '8', '8']
['30248']
**************************************************
['9月24日', 'の日']
<re.Match object; span=(0, 5), match='9月24日'>
group():9月24日、span():(0, 5)、start():0、end():5
['9月24日の日経平均株価は30248.8円']
7-2.stringライブラリ
「Python標準ライブラリ:string」では特定の文字列を出力できます。
[IN]
from string import ascii_letters
from string import ascii_lowercase
from string import ascii_uppercase
from string import digits
from string import hexdigits
from string import octdigits
from string import punctuation
from string import printable
from string import whitespace
print('ascii_letters:', ascii_letters)
print('ascii_lowercase:', ascii_lowercase)
print('ascii_uppercase:', ascii_uppercase)
print('digits:', digits)
print('hexdigits:', hexdigits)
print('octdigits:', octdigits)
print('punctuation:', punctuation)
print('printable:', printable)
print('whitespace:', whitespace)
[OUT]
ascii_letters: abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
ascii_lowercase: abcdefghijklmnopqrstuvwxyz
ascii_uppercase: ABCDEFGHIJKLMNOPQRSTUVWXYZ
digits: 0123456789
hexdigits: 0123456789abcdefABCDEF
octdigits: 01234567
punctuation: !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
printable: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
whitespace:
8.エスケープシーケンス
8-1.エスケープシーケンスとは
エスケープシーケンスとは記載した文字列ではなく条件に合わせた出力をしてくれる処理です。例として下記のような処理ができます。
[In]
print('改行を入れる\nこの先に\tを入れる。\n')
print('通常は\'はエラーが出るがエスケープシーケンスならエラーは出ない')
[Out]
改行を入れる
この先に を入れる。
通常は'はエラーが出るがエスケープシーケンスならエラーは出ない
Windowsの初学者あるあるとして正しいファイルパスを渡したのにエラーが出ることがあります。理由としてwindowsでの\の処理が思っている動作と異なるためです。
エラーを出さないためにエスケープシーケンスで処理するかraw文字列として(エスケープシーケンスと同等の形で扱ってくれる)処理します。
[In]
print('エスケープシーケンス無し:test\1\2\3')
print('エスケープシーケンス有り:test\\1\\2\\3')
print(r'raw文字列:test\1\2\3')
[Out]
エスケープシーケンス無し:test
エスケープシーケンス有り:test\1\2\3
raw文字列:test\1\2\3
8-2.X進数をASCIIコードに変換
機械が理解しやすい形のX進数を人間が理解しやすいASCII(American Standard Code for Information Interchange)への変換をエスケープシーケンスで実施してみます。
参考として対応表は下記の通りです。
[IN]
from string import digits
#8進数
print('\60') #8進数:0
print('\101') #8進数:A
#16進数:2桁
print('\x30') #16進数:0
print('\x41') #16進数:A
#16進数:4桁
print('\u0030') #16進数:0
print('\u0041') #16進数:A
[OUT]
0
A
0
A
0
A
9.参考資料
9-1.文字列の参照渡し/値渡し
Pythonの文字列は"="で渡すとそれぞれのオブジェクトは同じものを参照しますが、片方を更新すると自動的に別物として認識してくれるため不意のエラーは防止できます(List型は注意が必要)。
[IN]
a = 'aaa'
b = a #bにaをコピー
print(a, b)
print(id(a), id(b), id(a)==id(b)) #オブジェクトが同一か確認
b = b+'AAA' #bを別物に更新
print(a, b)
print(id(a), id(b), id(a)==id(b)) #オブジェクトが同一か確認
[OUT]
aaa aaa
139853233634800 139853233634800 True
aaa aaaAAA
139853233634800 139853208316400 False
9-2.Pythonライブラリ:トークナイザー
文字列を形態素(文字の最小単位)に分割する処理であり下記が有名です。
自然言語処理(日本語とか英語のテキストや音声を機械学習)をする人でないと多分使う機会がないため紹介とします。
あとがき
適宜修正予定
この記事が気に入ったらサポートをしてみませんか?