目次
スプレッドシートの1列に詰まった氏名を、区切り文字で列に分ける処理は、外部システムからのCSVデータ出力やフォームの入力結果を整理する現場で日常的に発生する。1つのセルの中に「姓」と「名」がカンマやスペースで結合された状態で入っていると、後の集計やメール送信、システム連携で支障をきたすため、早急に列を分割しなければならない。Google Apps Script (GAS) には、画面操作の機能に相当する splitTextToColumns というメソッドが用意されている。しかし、このメソッドは手軽に見えて、何も考えずに呼び出すと既存データを一瞬で破棄したり、見出し行を巻き込んでレイアウトを崩したりする強力かつ危険な側面を持っている。この記事では、GASを使って「スプレッドシート 区切り文字で列に分ける」処理を組み込む際に突き当たる落とし穴と、それを安全に処理するためのスクリプト構成について詳しくメモしておく。
splitTextToColumnsが起こす意図しない上書きと範囲指定の罠
splitTextToColumns メソッドを使用する際に最も注意すべきなのは、分割された文字列を展開する「右側の領域」に既存のデータが存在する場合、そのデータを何の警告もなく無条件で上書きしてしまうという仕様である。例えば、A列に氏名データがあり、B列に「社員番号」、C列に「所属部署」が配置されているシートがあったとする。この状態でA列に対して分割処理を実行すると、A列にあった「名」の部分がB列に書き込まれ、元々B列にあった社員番号は上書きされて消失してしまう。スプレッドシートの画面操作であれば直後に元に戻す操作(Ctrl+Z)が可能だが、GASによる自動処理で一度消去されたデータはスクリプト実行完了後に取り消すことができず、バックアップがなければ復元不能になる。
また、範囲指定に関する落とし穴も存在する。シート全体のデータ行に対して処理を適用しようとして getRange("A1:A") のように1行目から範囲を取得してしまうと、1行目に配置されている見出しセル(ヘッダー)までもが分割処理の対象になる。もし1行目の見出し文字列にたまたま区切り文字が含まれていた場合、見出し自体の列が分かれてしまい、シート全体の列構造が崩れる原因となる。仮に見出しに区切り文字が含まれていなくても、空行が含まれる範囲や不確定なデータ領域に対して安易に呼び出すと、セル位置のズレや不要なイベントの発生を引き起こす。さらに、標準の splitTextToColumns は指定した単一の区切り文字にしか対応しないため、文字列の中に異なる区切り文字(たとえば半角カンマと全角カンマ、スペースなど)が混在している場合、意図したように分割されずA列にデータが残ったまま右側に何も出力されないといった不整合が発生する。
A2:A全体への一括分割をGASで実行するスクリプト
1列に詰まった氏名データをA列から取得し、見出し行を除外した上で分割を行う基本的なスクリプトを示す。
function splitNameColumn() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
// 1行目の見出し(A1)を除外し、A2以降のデータ範囲を指定してカンマで列分割を行う
sheet.getRange("A2:A").splitTextToColumns(",");
}
このスクリプトを「いつ使うか」というと、他システムからエクスポートした生のCSVデータを新規シートのA列に貼り付けた直後など、B列以降にまだ何もデータが存在せず、見出し行を除く全データ行を一括で「姓」と「名」の2列(またはそれ以上)に素早く切り分けたいタイミングである。すでにB列以降が空であることが確定している環境においては、わずか数行の記述で大量のレコードを一括処理できるため、非常に利便性が高い。
しかし、この単純なコードには実務上でデータが「ずれる点」が存在する。まず、A2:A という開放範囲(最終行までの範囲)を指定して実行した場合、シート内にまだデータが入っていない空行まで対象に含まれるため、スプレッドシートの内部的な処理範囲が無駄に広がり、実行速度の低下や不必要な範囲更新を引き起こすことがある。また、氏名データの中にカンマが複数含まれている行(例:「山田,太郎,補佐」など)が存在すると、その行だけ右側に3列目まで展開され、周囲の2列想定のデータ構造と位置がずれてしまう。さらに前述の通り、見出し行を誤って含む範囲(A1:A など)を指定すると見出し自体が分解されて列名がズレるという問題が発生する。
これらの「ずれる点」に対する「回避」策としては、まず必ず見出し行である1行目を避けて A2:A のように2行目以降の Range オブジェクトを指定することが基本となる。加えて、データが実際に存在する最終行(getLastRow())を事前に取得し、必要な行数だけを明確に切り出した範囲に対して処理を行うことが望ましい。また、右側への食い出しによるデータのずれを防ぐため、分割前にデータ内の区切り文字の個数を検証するか、事前に右側へ必要な数だけ空列を挿入しておく防衛的なコード設計を組み合わせる必要がある。
氏名データ特有の全角半角の表記ゆれによる分割失敗の回避策
実務で扱う氏名データは、人間が手入力したものであれシステムから出力されたものであれ、区切り文字の表記ゆれが頻繁に発生する。「山田,太郎」のように半角カンマで区切られているケースもあれば、「佐藤,花子」のように全角カンマが使われていたり、「鈴木 太郎」のように半角スペースや全角スペースが混ざっていたりする。しかし、splitTextToColumns(",") は引数として渡された半角カンマしか認識しないため、全角カンマやスペースで区切られた行は分割処理を完全にスルーし、A列にそのまま残り続けてしまう。これが「一部の行だけ分割されない」という実務トラブルの直接的な原因になる。
この問題を回避するためには、splitTextToColumns を実行する前段階として、A列に存在する文字列全体の表記ゆれをあらかじめ単一の区切り文字(この場合は半角カンマ)へ統一(正規化)しておく処理を組み込むのが極めて効果的である。具体的には、GASの TextFinder 機能を使い、A列内の全角カンマ「,」、全角スペース「 」、半角スペース「 」、さらには読点「、」などをすべて半角カンマ「,」に置換してから分割を実行する。
テキスト置換による正規化を行っておけば、元データの表記にどのような揺れがあっても、splitTextToColumns(",") はすべての行を正確に検知して列分割を実行できるようになる。ただし、氏名自体に本来含まれるべき文字やハイフンなどを誤って置換しないよう、対象とする区切り文字の定義は慎重に行う必要がある。また、置換によって連続したカンマ(例:「,,」)が発生した場合は、分割後に空の列が余分に生成される原因になるため、連続する区切り文字をあらかじめ単一のカンマに圧縮する処理も施しておくと、分割結果の列ズレを完璧に防ぐことができる。
既存データの破壊を防ぐための事前列挿入パターン
すでに運用されている業務シートにおいて、A列に詰まった氏名データが存在し、B列やC列には既に他の重要な属性情報(部署名やメールアドレスなど)が入力されている場合、そのまま splitTextToColumns を実行するとB列以降のデータが上書き破壊されてしまう。この破壊挙動を完全に回避するためには、分割を実行する「前」の段階で、分割後に増える列の分だけB列の位置へ自動的に空の列を挿入するロジックを組むことが必須となる。
具体的な手順としては、まずA列の各セルに含まれる区切り文字の最大個数を判定するか、あるいは固定で想定される分割数(氏名であれば通常は「姓」と「名」の2列になるため、新たに1列分の空スペースが必要)を算出する。そして、GASの sheet.insertColumnAfter(1) や sheet.insertColumnsAfter(1, count) を呼び出して、A列の右側に空の列をあらかじめ押し込む。この処理によって、元々B列以降にあった既存データは右側へ自動的にスライド移動するため、データの上書き消失が物理的に起こらなくなる。
空列を安全に挿入した状態を作ってから範囲を指定して splitTextToColumns(",") を呼び出せば、新しく準備した空列へ安全に「名」などのデータが展開される。さらに処理の仕上げとして、1行目のヘッダー位置(A1セルとB1セル)に対して A1 に「姓」、B1 に「名」という適切な見出し文字列を再設定する補正処理まで自動化しておけば、シート全体のデータ構造を壊すことなく、完全に自動化された安全な列分割ワークフローが完成する。実務のスクリプト開発では、単に機能を呼び出すだけでなく、このようにシートの前後状態を保護する防犯策を組み込むことこそが重要である。

