業務データの文字列は「分けたい」と「くっつけたい」だらけです。名簿の氏名を姓と名に分割したい。住所から都道府県だけを取り出したい。「TK-2026-0042」のような商品コードを部位ごとに分解したい。逆に、バラバラの項目をカンマ区切りで 1 つにまとめたい。
C# なら string.Split 一発——ですが、加工結果をユーザーが画面上で見て、おかしい行だけ直せる形にしたいなら、スプレッドシートの数式でやるほうが向いています。Excel には LEFT・MID・FIND・SUBSTITUTE・TEXTJOIN という定番のテキスト関数群があり、ReoGrid は V4.5 でこれらに対応しました。この記事では業務データで本当によく使うレシピと落とし穴を整理し、同じ数式を WinForms / WPF アプリ内で動かすところまで解説します。
この記事は Excel 定番関数シリーズの続編です。「値を引く」 VLOOKUP / XLOOKUP、「条件で集計する」 SUMIF / COUNTIF、「日付を計算する」 EDATE / WORKDAY に続く「文字列を加工する」編です。
まず道具の整理 — 6 つの関数と 1 つの演算子
| 何をする関数か | 書式 | |
|---|---|---|
LEFT / RIGHT | 先頭 / 末尾から N 文字切り出す | LEFT(文字列, 文字数) |
MID | 途中から N 文字切り出す | MID(文字列, 開始位置, 文字数) |
FIND | 文字列の位置を探す | FIND(探す文字, 対象, [開始位置]) |
LEN | 文字数を数える | LEN(文字列) |
SUBSTITUTE | 文字列を置換する | SUBSTITUTE(対象, 検索, 置換, [何個目]) |
TEXTJOIN | 区切り文字を挟んで結合 | TEXTJOIN(区切り, 空を無視, 範囲...) |
& | 単純結合 | A2 & " " & B2 |
考え方はシンプルで、切る系(LEFT / RIGHT / MID)は「位置」を引数に取るので、位置を返す FIND と LEN を組み合わせて使います。「どこで切るか」を FIND が答え、「そこまで/そこから」を LEFT / MID が切る——この分業がテキスト数式の基本形です。
なお LEN は全角文字も 1 文字と数えます。「山田」は 2、「ヤマダ」は 3 です(Excel と同じ)。
レシピ 1 — 氏名を姓と名に分割する
名簿データの定番、「山田 太郎」をスペースで姓と名に分ける数式です。
A2: 山田 太郎
=LEFT(A2, FIND(" ", A2) - 1) → 山田 (姓)
=MID(A2, FIND(" ", A2) + 1, LEN(A2)) → 太郎 (名)
FIND(" ", A2) がスペースの位置(3)を返すので、その手前までを LEFT で、その次からを MID で切ります。MID の文字数に LEN(A2) を渡しているのは「残り全部」のイディオムです——長すぎる分は自動で切り詰められるので、正確な残り文字数を計算する必要はありません。
現実のデータは全角スペースが混ざっている
実務の名簿でこの数式が半分の行で #VALUE! になる理由は、ほぼこれです。「山田 太郎」——区切りが全角スペースの行が混在していて、FIND(" ", A2) が半角スペースを見つけられない。
対策は、探す前に SUBSTITUTE で区切りを揃えることです。
=LEFT(SUBSTITUTE(A2, " ", " "), FIND(" ", SUBSTITUTE(A2, " ", " ")) - 1)
数式が長くなるので、実務では正規化列を 1 本挟むほうがメンテしやすくなります。
B2: =TRIM(SUBSTITUTE(A2, " ", " ")) ← 全角→半角スペース + 前後の空白除去
C2: =IFERROR(LEFT(B2, FIND(" ", B2) - 1), B2) ← 姓(スペースなしはそのまま)
D2: =IFERROR(MID(B2, FIND(" ", B2) + 1, LEN(B2)), "") ← 名
スペースが 1 つも無い行(「山田太郎」と詰めて入力された行)では FIND がエラーになるので、IFERROR で「分割できない行は全体を姓に入れておく」と逃がしています。機械的に分割できない行は、無理に当てるのではなくユーザーの目に見える形で残す——これがシートで加工する最大の利点です。
全角・半角の混在がスペースだけでなく数字やカナにも及んでいるなら、先に 全角半角の正規化の記事 を読んでください。ASC / JIS 関数(V4.5 対応)で列ごと揃えられます。
レシピ 2 — 住所から都道府県を取り出す
これも日本の業務データの超定番です。ポイントは 1 つだけ——都道府県名は基本 3 文字ですが、神奈川県・和歌山県・鹿児島県の 3 つだけ 4 文字です。
有名なイディオムがあります。「4 文字目が『県』なら 4 文字、それ以外は 3 文字」。
A2: 神奈川県横浜市西区みなとみらい2-3-5
=IF(MID(A2, 4, 1) = "県", LEFT(A2, 4), LEFT(A2, 3)) → 神奈川県
「東京都」「大阪府」「北海道」はすべて 3 文字なので、この 1 行で 47 都道府県すべてを正しく分けられます。残りの住所は SUBSTITUTE の第 4 引数(何個目を置換するか)を使って、最初の 1 回だけ都道府県名を消します。
B2: =IF(MID(A2, 4, 1) = "県", LEFT(A2, 4), LEFT(A2, 3)) → 都道府県
C2: =SUBSTITUTE(A2, B2, "", 1) → 横浜市西区みなとみらい2-3-5
第 4 引数を省略すると全部置換されてしまう点に注意してください。「京都府京都市」のように同じ文字列が 2 回出る住所で差が出ます。
なお、郵便番号から住所を自動入力する仕組みごと作りたい場合は 郵便番号→住所オートコンプリートの記事 を参照してください。
レシピ 3 — 商品コードをハイフンで分解する
「TK-2026-0042」(拠点-年度-連番)のような固定書式のコードを分解します。1 個目の区切りは FIND で見つかりますが、2 個目はどうするか。FIND の第 3 引数(開始位置)を使って「1 個目の次から探す」のが基本形です。
A2: TK-2026-0042
=LEFT(A2, FIND("-", A2) - 1) → TK (拠点)
=MID(A2, FIND("-", A2) + 1,
FIND("-", A2, FIND("-", A2) + 1) - FIND("-", A2) - 1) → 2026 (年度)
=MID(A2, FIND("-", A2, FIND("-", A2) + 1) + 1, LEN(A2)) → 0042 (連番)
真ん中の数式が読みにくいと感じたら、それが正常な感覚です。区切りが 3 つ以上あるコードでは、SUBSTITUTE の「N 個目だけ置換」を使った小技のほうがきれいに書けます——N 個目の区切りだけを目印文字に変えてから探すという発想です。
=FIND("|", SUBSTITUTE(A2, "-", "|", 2)) → 2 個目のハイフンの位置
固定長のコード(拠点 2 桁 + 年度 4 桁…)なら、そもそも FIND は不要で MID(A2, 4, 4) と直接切ればよい、というのも実務では大事な判断です。
くっつける — TEXTJOIN と & の使い分け
分解の逆、結合には 3 つの書き方があります。
=C2 & " " & D2 → 山田 太郎 (少数の固定項目なら & が最速)
=CONCAT(A2:E2) → 区切りなしで全部連結
=TEXTJOIN(", ", TRUE, A2:E2) → 値1, 値2, 値3 (範囲をまとめて・空セルは飛ばす)
実務で効くのは TEXTJOIN の第 2 引数です。TRUE にすると空セルを飛ばして区切り文字を入れるので、「建物名が空の住所」「ミドルネームが無い名前」をつないでも , , のような区切りの連打になりません。備考欄の生成、CSV 風の 1 列出力、宛名ラベルの組み立てあたりで多用します。
落とし穴と現状の制限を正直に
FINDは大文字・小文字を区別します(Excel と同じ)。区別しないSEARCHは V4.5 時点では未対応なので、必要なら対象をUPPER/LOWERで揃えてからFINDしてください。ワイルドカード(*?)も使えません。- Excel 365 の新関数
TEXTSPLIT/TEXTBEFORE/TEXTAFTERは未対応です。この記事のFIND+LEFT/MIDの組み合わせが、そのまま代替になります(そして古い Excel との互換性もこちらのほうが上です)。 SUBSTITUTEは文字列を、REPLACEは位置を指定して置換します。「3 文字目から 4 文字を置き換える」ならREPLACE(A2, 3, 4, "****")——マスキング処理はこちらの担当です。
この数式を C# アプリの中で動かす
ReoGrid は V4.5 でこれらのテキスト関数群に対応しました。名簿インポート画面を想定して、貼り付けられた氏名列を姓・名に分割するシートを組んでみます。Office も Interop も不要です。
using unvell.ReoGrid;
var sheet = reoGridControl.CurrentWorksheet;
// ヘッダー
sheet["A1"] = new object[,] {
{ "氏名(入力)", "正規化", "姓", "名" }
};
// 取り込んだ生データ(全角スペース・スペースなしが混在)
sheet["A2"] = "山田 太郎";
sheet["A3"] = "佐藤 花子"; // 全角スペース
sheet["A4"] = "高橋一郎"; // スペースなし → 分割不能
// 数式列: 正規化 → 姓 → 名
for (int r = 1; r <= 3; r++)
{
int n = r + 1;
sheet[$"B{n}"] = $"=TRIM(SUBSTITUTE(A{n}, \" \", \" \"))";
sheet[$"C{n}"] = $"=IFERROR(LEFT(B{n}, FIND(\" \", B{n}) - 1), B{n})";
sheet[$"D{n}"] = $"=IFERROR(MID(B{n}, FIND(\" \", B{n}) + 1, LEN(B{n})), \"\")";
}
分割結果はセルに見えているので、「高橋一郎」の行だけユーザーが手で直せます。確定した値を C# 側に回収するのは GetCellData<T> です。
string lastName = sheet.GetCellData<string>("C2"); // 山田
string firstName = sheet.GetCellData<string>("D2"); // 太郎
一括処理で「もう画面はいらない、確定したから DB に入れたい」という段階になったら、数式列を値に置き換えて SetCellData で書き戻すか、最初から C# 側で string.Split に切り替えれば OK です。試行錯誤と目視確認はシートの数式で、確定後の大量処理は C# で——という分担が、この手のデータクレンジング画面のいちばん楽な作り方です。
まとめ
- 切る系(
LEFT/RIGHT/MID)は「位置」を引数に取る——位置はFINDとLENが答える - 氏名分割は
FIND(" ", …)が基本形。ただし実データは全角スペースが混在するので、先にSUBSTITUTE+TRIMで正規化列を作る - 都道府県抽出は「4 文字目が『県』なら 4 文字」の 1 行イディオムで 47 都道府県に対応できる
SUBSTITUTEの第 4 引数(N 個目だけ置換)は、残り住所の切り出しにも「N 個目の区切り探し」にも効く- 結合は少数項目なら
&、範囲まとめ + 空セルスキップならTEXTJOIN(区切り, TRUE, 範囲) SEARCH/TEXTSPLIT系は V4.5 時点で未対応——UPPER+FIND、FIND+MIDで代替する- ReoGrid V4.5 はこれらに対応。分割できない行がユーザーの目に見えて手で直せる、が数式でやる最大の利点
ReoGrid 4.5 の新機能を見る / 30 日トライアルを試す
