VBAMigrate

VBA → GAS 対応表

Excel VBA でよく使う書き方 15 種類と、Google Apps Script(GAS)での書き換え例です。このページの GAS のコードはすべてテスト環境で実行し、VBA と同じ結果になることを確認しています。

ブック全体を移行するなら:マクロを無料で診断する

特定の列の最終行

End(xlUp) は 1 つの列だけを見ます。sheet.getLastRow() はすべての列を見るため、列ごとに長さが違うと結果が変わります。

Excel VBA
Sub ShowLastRow()
    Dim last As Long
    last = Cells(Rows.Count, 1).End(xlUp).Row
    Range("C1").Value = last
End Sub
Google Apps Script
function ShowLastRow() {
  const sheet = SpreadsheetApp.getActiveSheet();
  sheet.getRange('C1').setValue(lastRowInColumn_(sheet, 1));
}

// Last non-empty row in one column (1 if the column is empty).
function lastRowInColumn_(sheet, col) {
  const values = sheet.getRange(1, col, Math.max(sheet.getLastRow(), 1), 1).getValues();
  for (let r = values.length - 1; r >= 0; r--) if (values[r][0] !== '') return r + 1;
  return 1;
}

✓ 確認済み: C1 = 2

行のループを速くする(まとめて読み書き)

getValue / setValue は 1 回ごとに通信が発生し、数十ミリ秒かかります。範囲をまとめて配列に読み込み、処理してから 1 回で書き戻します。

Excel VBA
Sub AddTax()
    Dim i As Long
    For i = 2 To 4
        Cells(i, 2).Value = Int(Cells(i, 1).Value * 1.1)
    Next i
End Sub
Google Apps Script
function AddTax() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const range = sheet.getRange(2, 1, 3, 2);
  const rows = range.getValues().map(([price]) => [price, Math.floor(price * 1.1)]);
  range.setValues(rows);
}

✓ 確認済み: B2 = 110 · B3 = 275 · B4 = 1098

MsgBox

メッセージボックスは SpreadsheetApp.getUi() のダイアログになります。

Excel VBA
Sub Hello()
    MsgBox "Done"
End Sub
Google Apps Script
function Hello() {
  SpreadsheetApp.getUi().alert('Done');
}

✓ 確認済み: Done

はい / いいえ の確認

vbYes の代わりに ui.Button.YES と比べます。

Excel VBA
Sub ConfirmClear()
    If MsgBox("Clear the sheet?", vbYesNo) = vbYes Then
        Range("A1").Value = ""
    End If
End Sub
Google Apps Script
function ConfirmClear() {
  const ui = SpreadsheetApp.getUi();
  if (ui.alert('Confirm', 'Clear the sheet?', ui.ButtonSet.YES_NO) === ui.Button.YES) {
    SpreadsheetApp.getActiveSheet().getRange('A1').setValue('');
  }
}

✓ 確認済み: A1 = "keep me"

InputBox(キャンセル対応)

InputBox はキャンセル時に空文字を返します。ui.prompt では押されたボタンで判定します。

Excel VBA
Sub AskName()
    Dim s As String
    s = InputBox("Your name?")
    If s = "" Then Exit Sub
    Range("A1").Value = s
End Sub
Google Apps Script
function AskName() {
  const ui = SpreadsheetApp.getUi();
  const res = ui.prompt('Your name?');
  if (res.getSelectedButton() !== ui.Button.OK || res.getResponseText() === '') return;
  SpreadsheetApp.getActiveSheet().getRange('A1').setValue(res.getResponseText());
}

✓ 確認済み: A1 = "Aiko"

Worksheets("名前") とシートがない場合

getSheetByName はエラーにならず null を返すため、VBA なら止まっていた箇所で確認が必要です。

Excel VBA
Sub CopyTotal()
    Worksheets("Report").Range("A1").Value = Worksheets("Data").Range("B2").Value
End Sub
Google Apps Script
function CopyTotal() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const data = ss.getSheetByName('Data');
  const report = ss.getSheetByName('Report');
  if (!data || !report) throw new Error('Sheet "Data" or "Report" not found');
  report.getRange('A1').setValue(data.getRange('B2').getValue());
}

✓ 確認済み: A1 = 42

Round(銀行型の丸め)

VBA の Round(2.5) は 2、Round(3.5) は 4 です。Math.round は .5 を常に切り上げるため、気づかないうちに結果が変わります。

Excel VBA
Sub RoundDemo()
    Range("A1").Value = Round(2.5)
    Range("A2").Value = Round(3.5)
    Range("A3").Value = Round(2.345, 2)
End Sub
Google Apps Script
function RoundDemo() {
  const sheet = SpreadsheetApp.getActiveSheet();
  sheet.getRange('A1:A3').setValues([[vbaRound_(2.5)], [vbaRound_(3.5)], [vbaRound_(2.345, 2)]]);
}

// VBA Round: halves go to the nearest even digit.
function vbaRound_(value, digits = 0) {
  const f = Math.pow(10, digits);
  const x = Number((value * f).toPrecision(15));
  const r = Math.round(x);
  return (Math.abs(x % 1) === 0.5 && r % 2 !== 0 ? r - 1 : r) / f;
}

✓ 確認済み: A1 = 2 · A2 = 4 · A3 = 2.34

Int・Fix・Mod(負の数と小数)

Int は切り下げ、Fix は 0 方向への切り捨て、Mod は計算前に両方を整数に丸めます(12.6 Mod 5 = 3)。

Excel VBA
Sub MathDemo()
    Range("A1").Value = Int(-2.5)
    Range("A2").Value = Fix(-2.5)
    Range("A3").Value = 12.6 Mod 5
End Sub
Google Apps Script
function MathDemo() {
  const sheet = SpreadsheetApp.getActiveSheet();
  sheet.getRange('A1:A3').setValues([[Math.floor(-2.5)], [Math.trunc(-2.5)], [vbaMod_(12.6, 5)]]);
}

function vbaMod_(a, b) {
  const toInt = (x) => (Math.abs(x % 1) === 0.5 ? 2 * Math.round(x / 2) : Math.round(x));
  return toInt(a) % toInt(b);
}

✓ 確認済み: A1 = -3 · A2 = -2 · A3 = 3

Left・Mid・Right・InStr

VBA の位置は 1 始まりで、InStr は見つからないと 0 を返します。JavaScript は 0 始まりで、indexOf は -1 を返します。

Excel VBA
Sub StringDemo()
    Dim s As String: s = "INV-2026-001"
    Range("A1").Value = Left(s, 3)
    Range("A2").Value = Mid(s, 5, 4)
    Range("A3").Value = Right(s, 3)
    Range("A4").Value = InStr(s, "2026")
    Range("A5").Value = InStr(s, "X")
End Sub
Google Apps Script
function StringDemo() {
  const s = 'INV-2026-001';
  const out = [
    s.slice(0, 3),
    s.substr(5 - 1, 4),   // Mid(s, 5, 4): start is 1-based
    s.slice(-3),
    s.indexOf('2026') + 1, // InStr: 1-based, 0 when missing
    s.indexOf('X') + 1,
  ];
  SpreadsheetApp.getActiveSheet().getRange(1, 1, out.length, 1).setValues(out.map((v) => [v]));
}

✓ 確認済み: A1 = "INV" · A2 = "2026" · A3 = "001" · A4 = 5 · A5 = 0

日付の書式(Format)

Utilities.formatDate をスプレッドシートのタイムゾーンで使います。月は MM(mm は分)です。

Excel VBA
Sub DateLabel()
    Range("A1").Value = "Issued " & Format(DateSerial(2026, 4, 1), "yyyy/mm/dd")
End Sub
Google Apps Script
function DateLabel() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const d = new Date(2026, 3, 1); // months are 0-based in JavaScript
  const text = Utilities.formatDate(d, ss.getSpreadsheetTimeZone(), 'yyyy/MM/dd');
  ss.getActiveSheet().getRange('A1').setValue('Issued ' + text);
}

✓ 確認済み: A1 = "Issued 2026/04/01"

月末日と月の加算

DateSerial(y, m + 1, 0) は new Date(y, m, 0) に相当します。DateAdd("m") は 1/31 の 1 か月後を 2/28 にしますが、setMonth だけだと 3/3 になります。

Excel VBA
Sub Dates()
    Range("A1").Value = Format(DateSerial(2026, 3, 0), "yyyy/mm/dd")
    Range("A2").Value = Format(DateAdd("m", 1, DateSerial(2026, 1, 31)), "yyyy/mm/dd")
End Sub
Google Apps Script
function Dates() {
  const tz = SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone();
  const fmt = (d) => Utilities.formatDate(d, tz, 'yyyy/MM/dd');
  SpreadsheetApp.getActiveSheet().getRange('A1:A2').setValues([
    [fmt(new Date(2026, 2, 0))],
    [fmt(addMonths_(new Date(2026, 0, 31), 1))],
  ]);
}

// Like VBA DateAdd("m"): keeps the day, clamped to the target month's length.
function addMonths_(date, n) {
  const d = new Date(date.getFullYear(), date.getMonth() + n, 1);
  const last = new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();
  d.setDate(Math.min(date.getDate(), last));
  return d;
}

✓ 確認済み: A1 = "2026/02/28" · A2 = "2026/02/28"

Scripting.Dictionary → Map

Exists → has、Item → get / set、Count → size、Keys → [...map.keys()]。

Excel VBA
Sub TotalsByCustomer()
    Dim d As Object, i As Long
    Set d = CreateObject("Scripting.Dictionary")
    For i = 2 To 5
        d(Cells(i, 1).Value) = d(Cells(i, 1).Value) + Cells(i, 2).Value
    Next i
    Range("D1").Value = d("A")
    Range("D2").Value = d.Count
End Sub
Google Apps Script
function TotalsByCustomer() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const totals = new Map();
  for (const [name, amount] of sheet.getRange(2, 1, 4, 2).getValues()) {
    totals.set(name, (totals.get(name) || 0) + amount);
  }
  sheet.getRange('D1:D2').setValues([[totals.get('A')], [totals.size]]);
}

✓ 確認済み: D1 = 17 · D2 = 3

On Error GoTo → try/catch(0 での割り算)

JavaScript は 0 で割ってもエラーにならず Infinity を返します。VBA がエラーに頼っていた箇所は、割る数を自分で確認します。

Excel VBA
Sub UnitPrice()
    On Error GoTo Failed
    Range("C1").Value = Range("A1").Value / Range("B1").Value
    Exit Sub
Failed:
    Range("C1").Value = "error"
End Sub
Google Apps Script
function UnitPrice() {
  const sheet = SpreadsheetApp.getActiveSheet();
  try {
    const [[total, qty]] = sheet.getRange('A1:B1').getValues();
    if (qty === 0 || qty === '') throw new Error('Division by zero');
    sheet.getRange('C1').setValue(total / qty);
  } catch (e) {
    sheet.getRange('C1').setValue('error');
  }
}

✓ 確認済み: C1 = "error"

ループで行を削除する

下から上へ削除するか、filter で残す行だけを作って 1 回で書き戻します(こちらが速い)。

Excel VBA
Sub RemoveDone()
    Dim i As Long
    For i = 5 To 2 Step -1
        If Cells(i, 2).Value = "done" Then Rows(i).Delete
    Next i
End Sub
Google Apps Script
function RemoveDone() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const range = sheet.getRange(2, 1, 4, 2);
  const keep = range.getValues().filter(([, status]) => status !== 'done');
  range.clearContent();
  if (keep.length) sheet.getRange(2, 1, keep.length, 2).setValues(keep);
}

✓ 確認済み: A2 = "b" · A3 = "d" · A4 = ""

Debug.Print

console.log を使います。出力は Apps Script の「実行数」ログに表示されます。

Excel VBA
Sub Trace()
    Debug.Print "rows: " & 3
End Sub
Google Apps Script
function Trace() {
  console.log('rows: ' + 3);
}

✓ 確認済み: rows: 3

ブック全体を移行するなら:マクロを無料で診断する

コード例は MIT ライセンスです。自由にコピーしてお使いください。