できない.dev

文字列を置換するには

文字列内の部分文字列を別の文字列へ置き換える基本形を各言語で示す。
全置換と最初の1回だけの置換、引数が正規表現として解釈される罠までを扱う。

公開:

Python 実行確認済み

s = "hello world, hello python"
print(s.replace("hello", "hi"))     # 全部置換
print(s.replace("hello", "hi", 1))  # 最初の1回だけ

str.replace は元の文字列を変更せず、置換後の新しい文字列を返す。
既定で全置換になるため、回数を制限したいときは第3引数 count を渡す。

JavaScript 実行確認済み

const s = "hello world, hello js";
console.log(s.replaceAll("hello", "hi")); // 全部置換
console.log(s.replace("hello", "hi"));    // 最初の1回だけ

replace は置換対象を文字列で指定すると最初の1回しか置換しない。
全置換には replaceAll を使うと、正規表現を持ち出さずに意図が明確になる。

TypeScript 実行確認済み

const s: string = "hello world, hello ts";
const replaced: string = s.replaceAll("hello", "hi");
console.log(replaced);
console.log(s.replace("hello", "hi")); // 最初の1回だけ

使い方は JavaScript と同じで、replaceAll は ES2021 以降の型定義に含まれる。
tsconfig の lib が古いと型エラーになるため es2021 以上を指定する。

Go 静的確認

package main
 
import (
	"fmt"
	"strings"
)
 
func main() {
	s := "hello world, hello go"
	fmt.Println(strings.ReplaceAll(s, "hello", "hi")) // 全部置換
	fmt.Println(strings.Replace(s, "hello", "hi", 1)) // 最初の1回だけ
}

strings.ReplaceAll は全置換で、回数を制限するときは strings.Replace に n を渡す。
n に -1 を渡すと ReplaceAll と同じ動作になる。

Java 静的確認

String s = "hello world, hello java";
System.out.println(s.replace("hello", "hi"));      // 全部置換(リテラル)
System.out.println(s.replaceFirst("hello", "hi")); // 最初の1回(正規表現)

replace は正規表現を使わないリテラルの全置換である。
replaceAll と replaceFirst は第1引数が正規表現として解釈されるため、ドットや括弧を含む文字列は Pattern.quote でエスケープする。

つまずき

JavaScript の replace は置換対象を文字列で指定すると最初の1回しか置換しない。
全置換のつもりで使うと2つ目以降が残るバグになりやすいので、replaceAll か正規表現の g フラグを使う。
逆に Java の replaceAll は第1引数が正規表現として解釈されるため、ドットや括弧を含む文字列をそのまま渡すと意図しない置換になる。
どの言語でも「全置換か1回だけか」と「引数が正規表現か文字列リテラルか」の2点を先に確認すると事故が減る。