この記事でわかること

  • 見た目は同じなのに、Excelの表の値が一致しない主な原因(前後の空白と全角・半角)
  • pandasのstr.normalize("NFKC")とstr.stripで、文字をそろえる手順
  • 元の表を変えずに、そろえた結果を別の列とファイルで確かめる方法
  • 数値のセルや丸数字など、そろえるときにつまずきやすいところ

取引先の名前や商品コードを集計すると、同じはずの値が別々に数えられることがあります。「ABC商事」と「ABC商事」、後ろに空白が付いた「ABC商事 」は、人の目には同じでも、Pythonでは違う文字列です。この記事では、PythonのpandasでExcelの表の文字の前後の空白と全角・半角をそろえる手順を、架空の表で実行して確かめた結果とあわせて紹介します。

説明の元にしたのは、PythonとpandasのAPIの資料で、2026年10月24日に読みました。コードは、作った架空の取引の表で実行しています。実在の会社や取引のデータは使っていません。

先に結論: NFKCでそろえてから前後の空白を取り、別の列に出す

先に結論を書くと、文字として読み込み、str.normalize("NFKC")で全角・半角をそろえてから、str.stripで前後の空白を取ります。結果は元の列を残したまま別の列に入れ、別のファイルに保存して確かめます。 主な違いと扱いは、次のとおりです。

違い そろえ方
全角の英数字 NFKCで半角
半角のカナ NFKCで全角
前後の空白 stripで取る
途中の空白 残る
数値のセル 文字で読む

見た目は同じでも一致しない理由

Unicodeでは、同じに見える文字を、いくつかの書き方で表せます。Pythonの資料では、互換の文字(たとえばローマ数字の「Ⅰ」とアルファベットの「I」)のように、ほかの文字とまとめられることが多い文字があるとしています。全角の「A」と半角の「A」も、文字としては別のものです。

また、セルの前や後ろに空白が入っていると、見た目はほとんど変わらないのに、別の値になります。集計や重複の確かめの前に、こうした違いをそろえておくと、同じ値を同じものとして数えられます。重複の見つけ方は、PythonでExcelの重複データを見つける手順で紹介しています。

NFKCとstr.stripの働き

Pythonのunicodedata.normalizeでは、正規化の形として「NFC」「NFKC」「NFD」「NFKD」の4つを選べます。資料によると、NFKCは、互換の文字を同じ意味の文字に置き換える分解をしてから、組み立て直す形です。pandasのSeries.str.normalizeも、同じ4つの形を指定でき、詳しい説明はunicodedata.normalizeを見るよう案内しています。

前後の空白を取るのはstr.stripです。pandasの資料では、Series.str.stripは、何も指定しなければ、改行を含む前後の空白を取り除くとしています。また、文字でない値は欠損値(NaN)に置き換えるとしています。この点は、後の「つまずきやすいところ」で触れます。

手順: 文字として読み、そろえた列を足して保存する

次のコードは、作業用のフォルダーにある架空の取引の表(orders.xlsx)の「取引先」と「商品コード」の列をそろえ、結果を別のファイル(orders_normalized.xlsx)に保存します。元の表は読むだけで、書き換えません。自分の表で使うときは、ファイル名と列名を合わせ、元のファイルの写しを残してから実行します。

import pandas as pd

# すべての列を文字として読む(元の表は読むだけで書き換えない)
df = pd.read_excel("orders.xlsx", dtype=str)
cols = ["取引先", "商品コード"]

for col in cols:
    # 全角・半角をそろえ(NFKC)、前後の空白を取る
    after = df[col].str.normalize("NFKC").str.strip()
    changed = df[col].notna() & (df[col] != after)
    print(col, "前", df[col].nunique(), "種類 → 後", after.nunique(), "種類 / 変わったセル", int(changed.sum()))
    df[col + "_そろえた後"] = after

# 結果は別のファイルに保存する
df.to_excel("orders_normalized.xlsx", index=False)
print(df[["取引先", "取引先_そろえた後"]].to_string(index=False))

Pythonとpandas、Excelのファイルを読むためのopenpyxlを入れた環境で、表と同じフォルダーで実行します。to_excelのindex=Falseは、行の番号の列を保存しないための指定です。

実行した結果

架空の表(6行)で試すと、取引先は「前 6 種類 → 後 2 種類 / 変わったセル 4」、商品コードは「前 5 種類 → 後 2 種類 / 変わったセル 3」と表示されました。

  • 全角の「ABC商事」は、半角の「ABC商事」になりました
  • 後ろに半角の空白がある「ABC商事 」と、前に全角の空白がある「 ABC商事」も、「ABC商事」になりました
  • 半角のカナの「ヤマダ商店」は、全角の「ヤマダ商店」になりました
  • 全角の「A-101」は、半角の「A-101」になりました

orders_normalized.xlsxには、元の列とそろえた後の列が並んで保存され、元のorders.xlsxは変わりませんでした。検証に使った作業PCの環境は、Python 3.12.10とpandas 3.0.6、Excelのファイルを扱うopenpyxl 3.1.5の組み合わせです。

自分で直すか、相談するかの判断

判断の目安は、「そろえた後の列を見て、変わったセルに納得できるか」です。全角・半角や前後の空白だけが変わっているなら、そろえた列を集計や重複の確かめに使います。空欄の扱いは、PythonでExcelの表の空欄を見つけて一覧にする手順で紹介しています。

商品コードや顧客の番号のように、表記がほかの仕組みとつながっている値は、勝手にそろえると照合できなくなることがあります。変わったセルの一覧を持って、その表を作った人や、データを使う部署の人と、どの表記を正しいものにするかを決めます。

つまずきやすいところ

  • 数値のセルが欠損値になる: dtype=strを付けずに読むと、数字だけの商品コードは数値として読まれ、架空の表ではそろえた後に欠損値(NaN)になりました。文字として読みます
  • 途中の空白は残る: str.stripは前後だけを取ります。架空の表でも、「ABC 商事」の間の全角の空白は、半角の空白に変わっただけで残りました
  • そろえすぎる文字がある: 架空の表では、丸数字の「①」は「1」に、「㈱」は「(株)」に変わりました。会社の名前などで使っている場合は、変わったセルを確かめます
  • すべての横線はそろわない: 長音の「ー」とマイナスの記号「−」は、NFKCの後も別の文字のままでした。商品コードの区切りの線がばらばらな場合は、別に置き換えを決めます
  • CSVで集計するとき: 読み込みの段階でそろえておくと、後の集計がずれにくくなります。CSVの集計は、PythonでCSVを集計する手順で紹介しています

まとめ

  • 見た目が同じでも、全角・半角や前後の空白が違うと、Pythonでは別の値になります
  • read_excelのdtype=strで文字として読み、str.normalize("NFKC")のあとstr.stripで前後の空白を取ります
  • 結果は別の列と別のファイルに出し、元の表は書き換えません
  • 丸数字や「㈱」も変わり、横線はすべてはそろわないため、変わったセルを確かめてから使います