名簿や取引先リストによくある「表記のゆれ」を、ルールを決めて一括で整えるツールです。 手作業だと1件ずつ目視で直す必要がある作業を、貼り付けてボタン1回で終わらせます。
※ このページはポートフォリオ用のデモです。掲載データはすべて架空のものです。
入力したデータはブラウザの中だけで処理され、サーバーには一切送信されません。
「整形を実行する」を押すと、ここに結果が表示されます。
Excel VBA のマクロにして、ボタン1つで同じシート上を整形します。ファイルを開いたまま完結します。
GAS(Google Apps Script)でメニューを追加し、共有シートを開いた全員が同じ処理を実行できます。
Python スクリプトにして、フォルダ内のCSVをまとめて処理します。定期実行の設定まで対応できます。
# 顧客リストの表記ゆれを整えて1本のCSVにまとめる import re, unicodedata, glob import pandas as pd def to_hankaku(s: str) -> str: # 全角の英数字・記号を半角へ(カタカナは全角のまま残す) return unicodedata.normalize("NFKC", str(s)).strip() def format_tel(s: str) -> str: d = re.sub(r"\D", "", to_hankaku(s)) # 数字以外を除去 if len(d) == 11: # 携帯 090-1234-5678 return f"{d[:3]}-{d[3:7]}-{d[7:]}" if len(d) == 10: # 固定 092-123-4567 return f"{d[:3]}-{d[3:6]}-{d[6:]}" return to_hankaku(s) # 想定外はそのまま残して目視確認 def format_zip(s: str) -> str: d = re.sub(r"\D", "", to_hankaku(s)) return f"{d[:3]}-{d[3:]}" if len(d) == 7 else to_hankaku(s) frames = [] for path in glob.glob("input/*.csv"): df = pd.read_csv(path, dtype=str).fillna("") df["氏名"] = df["氏名"].map(lambda s: re.sub(r"[\s ]+", " ", to_hankaku(s))) df["電話番号"] = df["電話番号"].map(format_tel) df["郵便番号"] = df["郵便番号"].map(format_zip) df["メールアドレス"] = df["メールアドレス"].map(lambda s: to_hankaku(s).lower()) df["会社名"] = df["会社名"].map(lambda s: to_hankaku(s).replace("(株)", "株式会社")) frames.append(df) out = pd.concat(frames, ignore_index=True) before = len(out) out = out.drop_duplicates(subset="電話番号", keep="first") # 電話番号で名寄せ out.to_csv("整形済み顧客リスト.csv", index=False, encoding="utf-8-sig") print(f"{before}件 → {len(out)}件(重複 {before - len(out)}件を削除)")
// スプレッドシートに「データ整形」メニューを追加して実行する function onOpen() { SpreadsheetApp.getUi() .createMenu('データ整形') .addItem('顧客リストを整形する', 'cleanCustomerList') .addToUi(); } function cleanCustomerList() { const sheet = SpreadsheetApp.getActiveSheet(); const range = sheet.getDataRange(); const rows = range.getValues(); const head = rows.shift(); const col = name => head.indexOf(name); const seen = {}; const cleaned = []; let removed = 0; rows.forEach(row => { row[col('氏名')] = toHankaku(row[col('氏名')]).replace(/[\s ]+/g, ' '); row[col('電話番号')] = formatTel(row[col('電話番号')]); row[col('郵便番号')] = formatZip(row[col('郵便番号')]); row[col('メールアドレス')] = toHankaku(row[col('メールアドレス')]).toLowerCase(); row[col('会社名')] = toHankaku(row[col('会社名')]).replace('(株)', '株式会社'); const key = row[col('電話番号')]; if (key && seen[key]) { removed++; return; } // 電話番号で重複判定 seen[key] = true; cleaned.push(row); }); range.clearContent(); sheet.getRange(1, 1, cleaned.length + 1, head.length) .setValues([head].concat(cleaned)); SpreadsheetApp.getUi().alert( rows.length + '件 → ' + cleaned.length + '件(重複 ' + removed + '件を削除しました)'); } function toHankaku(v) { return String(v).trim().replace(/[A-Za-z0-9]/g, s => String.fromCharCode(s.charCodeAt(0) - 0xFEE0)); } function formatTel(v) { const d = toHankaku(v).replace(/\D/g, ''); if (d.length === 11) return d.slice(0,3) + '-' + d.slice(3,7) + '-' + d.slice(7); if (d.length === 10) return d.slice(0,3) + '-' + d.slice(3,6) + '-' + d.slice(6); return toHankaku(v); } function formatZip(v) { const d = toHankaku(v).replace(/\D/g, ''); return d.length === 7 ? d.slice(0,3) + '-' + d.slice(3) : toHankaku(v); }
' Excelのシート上の顧客リストをその場で整形する(Alt+F8 で実行) Option Explicit Sub 顧客リストを整形する() Dim ws As Worksheet, lastRow As Long, i As Long Dim seen As Object, key As String, removed As Long Set ws = ActiveSheet Set seen = CreateObject("Scripting.Dictionary") lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row Application.ScreenUpdating = False For i = lastRow To 2 Step -1 ' 行削除があるので下から走査する ws.Cells(i, 1).Value = 半角化(ws.Cells(i, 1).Value) ' 氏名 ws.Cells(i, 2).Value = 電話整形(ws.Cells(i, 2).Value) ' 電話番号 ws.Cells(i, 3).Value = 郵便整形(ws.Cells(i, 3).Value) ' 郵便番号 ws.Cells(i, 4).Value = LCase(半角化(ws.Cells(i, 4).Value)) ' メール ws.Cells(i, 5).Value = Replace(半角化(ws.Cells(i, 5).Value), "(株)", "株式会社") key = CStr(ws.Cells(i, 2).Value) If key <> "" Then If seen.Exists(key) Then ws.Rows(i).Delete ' 電話番号が重複している行を削除 removed = removed + 1 Else seen.Add key, True End If End If Next i Application.ScreenUpdating = True MsgBox "整形が完了しました。重複 " & removed & " 件を削除しました。", vbInformation End Sub Private Function 半角化(v As Variant) As String 半角化 = Trim(StrConv(CStr(v), vbNarrow)) End Function Private Function 電話整形(v As Variant) As String Dim s As String, d As String, i As Long s = 半角化(v) For i = 1 To Len(s) If Mid(s, i, 1) Like "#" Then d = d & Mid(s, i, 1) Next i If Len(d) = 11 Then 電話整形 = Left(d, 3) & "-" & Mid(d, 4, 4) & "-" & Right(d, 4) ElseIf Len(d) = 10 Then 電話整形 = Left(d, 3) & "-" & Mid(d, 4, 3) & "-" & Right(d, 4) Else 電話整形 = s End If End Function Private Function 郵便整形(v As Variant) As String Dim s As String, d As String, i As Long s = 半角化(v) For i = 1 To Len(s) If Mid(s, i, 1) Like "#" Then d = d & Mid(s, i, 1) Next i If Len(d) = 7 Then 郵便整形 = Left(d, 3) & "-" & Right(d, 4) Else 郵便整形 = s End Function