- Kotlin
Kotlin 正規表現 Regexの使い方 find・replace
Kotlin の正規表現は Regex クラスで扱います。Regex("""\d+""") でパターンを作り、全体が一致するかは matches、一部に含まれるかは containsMatchIn、取り出しは find / findAll、置き換えは replace、分割は split を使います。
この記事では、9つの関数の戻り値と用途を一覧にし、全体一致と部分一致の取り違え、グループの取り出し方3種類、ラムダ置換、$ のエスケープ、RegexOption、raw 文字列の書き分け、パターンの書き間違いで出る例外までを、すべて実行した出力と一緒に示します。
確認環境:Ubuntu 24.04 / Kotlin 2.4.20(kotlinc、JVM 向け)/ OpenJDK 21.0.10。Kotlin/JVM の Regex は java.util.regex を土台にしているため、例外文は Java のものが表示されます。
Kotlin Regex の早見表
| 関数 | 戻り値 | 一致の範囲 | 用途 |
|---|---|---|---|
matches(input) |
Boolean | 全体 | 入力チェック(形式が合っているか) |
matchEntire(input) |
MatchResult? | 全体 | 入力チェックをしつつ、グループも取り出す |
matchAt(input, index) |
MatchResult? | 指定位置から | 文字列の途中の決まった位置で一致を調べる(Kotlin 1.7 から) |
containsMatchIn(input) |
Boolean | 部分 | 含まれているかを調べる |
find(input) |
MatchResult? | 部分(最初の1件) | 最初の一致を取り出す |
findAll(input) |
MatchResult の Sequence | 部分(すべて) | 一致をすべて取り出す |
replace(input, replacement) |
String | 部分(すべて) | すべて置き換える。ラムダも渡せる |
replaceFirst(input, replacement) |
String | 部分(最初の1件) | 最初の1件だけ置き換える |
split(input) |
String の List | 部分(すべて) | 一致した箇所を区切りにして分ける |
| MatchResult から取り出すもの | 書き方 | 中身 |
|---|---|---|
| 一致した文字列 | m.value |
String |
| 位置 | m.range |
IntRange |
| グループ(リスト) | m.groupValues[1] |
String。0 番は全体。一致しなかったグループは空文字 |
| グループ(変数へ分ける) | val (a, b) = m.destructured |
1 番から順に入る |
| 名前付きグループ | m.groups["name"]?.value |
一致しなかったグループは null |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Kotlin 正規表現 Regexの使い方 find・replace」
まず動かす:9つの関数を同じ文字列で試す
fun main() {
val re = Regex("""\d+""") // 数字が1個以上
val text = "注文A-120、注文B-45"
println(re.matches("120")) // 全体が一致するか
println(re.matches(text))
println(re.containsMatchIn(text)) // 一部でも一致するか
println(re.find(text)?.value) // 最初の一致
println(re.findAll(text).map { it.value }.toList()) // すべての一致
println(re.replace(text, "#")) // すべて置換
println(re.replaceFirst(text, "#")) // 最初だけ置換
println(re.split(text)) // 一致した箇所で分割
println(re.matchEntire("120")?.value) // 全体一致の MatchResult
println(re.matchEntire(text)?.value)
println(re.matchAt(text, 4)?.value) // 指定した位置から一致するか
println(re.matchAt(text, 0)?.value)
println(re.matchesAt(text, 4))
}
kotlinc overview.kt -include-runtime -d overview.jar
java -Dstdout.encoding=UTF-8 -jar overview.jar
-Dstdout.encoding=UTF-8 は、日本語の出力を UTF-8 で表示するための指定です。
true
false
true
120
[120, 45]
注文A-#、注文B-#
注文A-#、注文B-45
[注文A-, 、注文B-, ]
120
null
120
null
true
matchAt は「その位置からちょうど一致が始まるか」を調べます。4文字目(0 始まり)は 1 なので一致し、0文字目は「注」なので null です。Boolean だけほしいときは matchesAt を使います。split の結果の最後が空文字なのは、文字列の末尾が一致で終わっているためです。
全体一致と部分一致の取り違えを出力で確かめる
入力チェックでよくあるつまずきが、全体一致(matches)のつもりで部分一致(containsMatchIn)を使うことです。
fun main() {
val digits = Regex("""\d{3}""") // 数字3桁
val inputs = listOf("123", "1234", "abc123", "12")
println("入力 matches containsMatchIn matchEntire find")
for (s in inputs) {
println(
"%-9s %-8s %-16s %-12s %s".format(
s,
digits.matches(s),
digits.containsMatchIn(s),
digits.matchEntire(s)?.value,
digits.find(s)?.value,
)
)
}
// String 側の関数でも同じ区別がある
println("1234".matches(digits)) // 全体一致
println("1234".contains(digits)) // 部分一致
println(digits in "1234") // contains と同じ意味
// 入力チェックを部分一致で書くと通ってしまう例
val code = Regex("""[A-Z]{2}-\d{4}""")
val input = "xxAB-12345yy"
println("containsMatchIn: " + code.containsMatchIn(input))
println("matches : " + code.matches(input))
// ^ と $ を付ければ containsMatchIn でも全体一致の意味になる
println("^...$ + contains: " + Regex("""^[A-Z]{2}-\d{4}$""").containsMatchIn(input))
}
入力 matches containsMatchIn matchEntire find
123 true true 123 123
1234 false true null 123
abc123 false true null 123
12 false false null null
false
true
true
containsMatchIn: true
matches : false
^...$ + contains: false
「数字3桁」のパターンに対して、1234 や abc123 は containsMatchIn だと true になります。形式のチェックには matches か matchEntire を使います。 文字列側から書く場合は、"1234".matches(regex) が全体一致、"1234".contains(regex) と regex in "1234" が部分一致です。
| 目的 | Regex 側 | String 側 |
|---|---|---|
| 全体が形式どおりか | re.matches(s) / re.matchEntire(s) |
s.matches(re) |
| 一部に含まれるか | re.containsMatchIn(s) |
s.contains(re) / re in s |
グループの取り出し:groupValues・destructured・名前付き
丸かっこで囲んだ部分(グループ)は、3つの方法で取り出せます。
fun main() {
val re = Regex("""(\d{4})-(\d{2})-(\d{2})""")
val m = re.find("公開日: 2026-10-05 更新")!!
// groupValues:0 番が全体、1 番からが丸かっこの中身
println(m.value)
println(m.groupValues)
println(m.groupValues[1] + "年")
println(m.range)
// destructured:グループを順に変数へ(全体は含まない)
val (year, month, day) = m.destructured
println("$year / $month / $day")
// 名前付きグループ:(?<名前>...) と groups["名前"]
val named = Regex("""(?<user>[\w.]+)@(?<domain>[\w.]+)""")
val nm = named.find("連絡先 taro.yamada@example.com まで")!!
println(nm.groups["user"]?.value)
println(nm.groups["domain"]?.value)
println(nm.groups[1]?.value + " " + nm.groups[1]?.range)
// 一致しなかった省略可能なグループ
val opt = Regex("""(\d+)(px|em)?""")
val om = opt.find("幅 120")!!
println(om.groupValues) // 一致しなかったグループは空文字
println(om.groups[2]) // groups では null
// findAll と組み合わせて全部取り出す
val pairs = Regex("""(\w+)=(\d+)""")
.findAll("apple=120, banana=80, cherry=300")
.map { it.groupValues[1] to it.groupValues[2].toInt() }
.toMap()
println(pairs)
// 無い名前を指定するとエラーになる
try {
nm.groups["host"]
} catch (e: Exception) {
println("${e::class.qualifiedName}: ${e.message}")
}
// 見つからないときの find は null
println(re.find("日付なし"))
}
2026-10-05
[2026-10-05, 2026, 10, 05]
2026年
5..14
2026 / 10 / 05
taro.yamada
example.com
taro.yamada 4..14
[120, 120, ]
null
{apple=120, banana=80, cherry=300}
java.lang.IllegalArgumentException: No group with name <host>
null
| 方法 | 向く場面 | 気をつける点 |
|---|---|---|
groupValues[n] |
グループが1〜2個で、手早く取りたい | 0 番は一致全体。一致しなかったグループは空文字 |
destructured |
グループを全部、名前を付けた変数で受けたい | 全体は含まれず 1 番から。変数の数はグループの数以内にする(超えると IndexOutOfBoundsException) |
groups["name"] |
グループが多い、あとからパターンを直す可能性がある | 戻り値は MatchGroup? なので ?.value。パターンに無い名前は IllegalArgumentException |
find は一致が無いと null を返します。上のコードでは説明を短くするために !! を使っていますが、入力が決まっていない場面では ?. や ?: return で null を受けます。
置換:文字列・グループ参照・ラムダ
fun main() {
val text = "apple 120円, banana 80円"
// 文字列で置換
println(Regex("""\d+""").replace(text, "N"))
println(Regex("""\d+""").replaceFirst(text, "N"))
// グループ参照:$1 / ${name}
println(Regex("""(\w+) (\d+)円""").replace(text, "$2円の$1"))
println(Regex("""(?<name>\w+) (?<price>\d+)円""").replace(text, "\${price}:\${name}"))
// ラムダ置換:一致ごとに計算して置き換える
println(Regex("""\d+""").replace(text) { m -> (m.value.toInt() * 2).toString() })
println(Regex("""\b[a-z]""").replace(text) { it.value.uppercase() })
println(Regex("""(\w+) (\d+)円""").replace(text) { m ->
val (name, price) = m.destructured
"$name=${"%,d".format(price.toInt() * 100)}"
})
// 置換後の文字列に $ をそのまま入れたいとき
try {
println(Regex("""\d+円""").replace(text, "$ 5"))
} catch (e: Exception) {
println("${e::class.qualifiedName}: ${e.message}")
}
println(Regex("""\d+円""").replace(text, "\\$5"))
println(Regex("""\d+円""").replace(text, Regex.escapeReplacement("$5")))
println(Regex("""\d+円""").replace(text) { "$5" }) // ラムダの戻り値はそのまま使われる
// パターン側の記号をそのまま探したいとき
println(Regex("1+1").containsMatchIn("1+1=2"))
println(Regex(Regex.escape("1+1")).containsMatchIn("1+1=2"))
println(Regex.escape("1+1"))
println(Regex.fromLiteral("a.b").containsMatchIn("axb") to Regex("a.b").containsMatchIn("axb"))
// String.replace は第1引数が String なら正規表現ではなく文字そのもの
println("a.b.c".replace(".", "-"))
println("a.b.c".replace(Regex("."), "-"))
}
apple N円, banana N円
apple N円, banana 80円
120円のapple, 80円のbanana
120:apple, 80:banana
apple 240円, banana 160円
Apple 120円, Banana 80円
apple=12,000, banana=8,000
java.lang.IllegalArgumentException: Illegal group reference
apple $5, banana $5
apple $5, banana $5
apple $5, banana $5
false
true
\Q1+1\E
(false, true)
a-b-c
-----
置換のポイント
- 置換後の文字列では
$1や${name}がグループの参照になります。 Kotlin の通常の文字列では${...}が文字列テンプレートとして先に働くので、名前付きの参照は"\${price}"のように $ の前へバックスラッシュを置きます。"$2円の$1"のように $ の直後が数字の場合は、テンプレートにならずそのまま渡ります。 - 計算して置き換えるときはラムダを渡します。 ラムダは MatchResult を受け取り、戻り値がそのまま置換後の文字列になります。
- 置換後に $ という文字そのものを入れたいときは、
"\\$5"と書くか、Regex.escapeReplacement("$5")を通すか、ラムダで返します。そのまま"$ 5"を渡すとIllegal group referenceになります。 - パターン側で記号をそのまま探したいときは
Regex.escape("1+1")かRegex.fromLiteral("a.b")を使います。 - String.replace は、第1引数が String なら正規表現として扱いません。
"a.b.c".replace(".", "-")は a-b-c、replace(Regex("."), "-")は全部の文字が置き換わって ----- になります。
分割:split
fun main() {
println(Regex("""\s*,\s*""").split("apple , banana,cherry , melon"))
println(Regex("""\s+""").split(" a b c "))
println(" a b c ".trim().split(Regex("""\s+""")))
println(Regex(",").split("a,b,c,d", limit = 2))
println(Regex("""[,;/]""").split("a,b;c/d"))
println(Regex("""(?<=\d)(?=[a-z])""").split("12ab34cd"))
println(Regex(",").splitToSequence("a,b,c").map { it.uppercase() }.toList())
}
[apple, banana, cherry, melon]
[, a, b, c, ]
[a, b, c]
[a, b,c,d]
[a, b, c, d]
[12, ab34, cd]
[A, B, C]
前後に空白がある文字列を \s+ で分けると、先頭と末尾に空文字が入ります。 先に trim() しておくと要素だけが残ります。limit は分ける個数の上限で、2 を渡すと最初の区切りだけで分かれます。
RegexOption の一覧
fun main() {
for (o in RegexOption.entries) println("${o.name} value=${o.value} mask=${o.mask}")
val text = "Kotlin\nkotlin regex\nJAVA"
println(Regex("kotlin").findAll(text).count())
println(Regex("kotlin", RegexOption.IGNORE_CASE).findAll(text).count())
println(Regex("^[a-zA-Z]+$").findAll(text).map { it.value }.toList())
println(Regex("^[a-zA-Z]+$", RegexOption.MULTILINE).findAll(text).map { it.value }.toList())
println(Regex("Kotlin.kotlin").containsMatchIn(text))
println(Regex("Kotlin.kotlin", RegexOption.DOT_MATCHES_ALL).containsMatchIn(text))
val commented = Regex(
"""
(\d{3}) # 前半3桁
- # 区切り
(\d{4}) # 後半4桁
""",
RegexOption.COMMENTS,
)
println(commented.find("番号 123-4567")?.groupValues)
println(Regex("a.c", RegexOption.LITERAL).containsMatchIn("abc") to Regex("a.c", RegexOption.LITERAL).containsMatchIn("a.c"))
// 複数指定は Set で渡す。パターンの中に (?i) と書く方法もある
val both = Regex("^java$", setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE))
println(both.find(text)?.value)
println(Regex("(?im)^java$").find(text)?.value)
println(both.options)
}
IGNORE_CASE value=2 mask=2
MULTILINE value=8 mask=8
LITERAL value=16 mask=16
UNIX_LINES value=1 mask=1
COMMENTS value=4 mask=4
DOT_MATCHES_ALL value=32 mask=32
CANON_EQ value=128 mask=128
1
2
[]
[Kotlin, JAVA]
false
true
[123-4567, 123, 4567]
(false, true)
JAVA
JAVA
[IGNORE_CASE, MULTILINE]
| RegexOption | 働き | パターン内の書き方 |
|---|---|---|
| IGNORE_CASE | 大文字と小文字を区別しない | (?i) |
| MULTILINE | ^ と $ が各行の先頭と末尾に一致する |
(?m) |
| DOT_MATCHES_ALL | . が改行にも一致する |
(?s) |
| COMMENTS | パターンの中に空白と # から始まるコメントを書ける | (?x) |
| LITERAL | パターン全体を文字そのものとして扱う | Regex.fromLiteral でも同じ |
| UNIX_LINES | 行の区切りを \n だけにする | (?d) |
| CANON_EQ | 正準分解で等しい文字を同じとみなす | なし |
公式の API リファレンスによると、IGNORE_CASE と MULTILINE はすべての対象(JVM・JS・Native・Wasm)で使え、残りの5つは JS を除く対象で使えます。複数指定するときは setOf(...) で渡します。
raw 文字列と通常文字列の書き分け
fun main() {
// 通常の文字列:バックスラッシュを2つ重ねる
val normal = Regex("\\d+\\.\\d+")
// raw 文字列(""" で囲む):バックスラッシュは1つでよい
val raw = Regex("""\d+\.\d+""")
// toRegex() でも作れる
val ext = """\d+\.\d+""".toRegex()
println(normal.pattern)
println(raw.pattern)
println(normal.pattern == raw.pattern)
println(ext.find("値は 3.14 です")?.value)
// バックスラッシュそのものを探す
val path = """C:\work\memo.txt"""
println(Regex("\\\\").split(path)) // 通常の文字列では4つ
println(Regex("""\\""").split(path)) // raw 文字列では2つ
// raw 文字列の中でも $ は文字列テンプレートとして働く
val unit = "円"
println(Regex("""\d+$unit""").find("120円")?.value)
// 行末の $ は、後ろに名前が続かなければそのまま書ける
println(Regex("""^\d+$""").matches("120"))
// $ の後ろに英字が続く形をそのまま書きたいときは ${'$'}
println(Regex("""\${'$'}price""").pattern)
println(Regex("""\${'$'}price""").containsMatchIn("単価は \$price です"))
// raw 文字列の中に " を書く
println(Regex("""name="(\w+)"""").find("""<input name="email">""")?.groupValues?.get(1))
}
\d+\.\d+
\d+\.\d+
true
3.14
[C:, work, memo.txt]
[C:, work, memo.txt]
120円
true
\$price
true
email
| 書きたいもの | 通常の文字列 "..." | raw 文字列 """...""" |
|---|---|---|
数字 \d |
"\\d" |
"""\d""" |
| ピリオドそのもの | "\\." |
"""\.""" |
| バックスラッシュそのもの | "\\\\" |
"""\\""" |
行末の $ |
"$"(後ろに名前が続かなければそのまま) |
同じ |
| $ の後ろに英字が続く形 | "\\\$price" |
"""\${'$'}price""" |
| ダブルクォート | "\"" |
そのまま書ける |
正規表現は raw 文字列で書くと、バックスラッシュを重ねずに済み、パターンがそのまま読めます。 raw 文字列でも $unit のような文字列テンプレートは働くので、変数を埋め込むこともできます。変数の中身を文字そのものとして扱いたいときは Regex.escape(変数) を通してから埋め込みます。
パターンの書き間違いで出る PatternSyntaxException
パターンの文法に誤りがあると、Regex を作る時点で java.util.regex.PatternSyntaxException が出ます。メッセージには、説明・位置・パターン・位置を指す ^ が含まれます。
import java.util.regex.PatternSyntaxException
fun tryRegex(pattern: String) {
try {
Regex(pattern)
println("OK: $pattern")
} catch (e: PatternSyntaxException) {
println("--- $pattern ---")
println(e.message)
println("description=${e.description} index=${e.index}")
}
}
fun main() {
tryRegex("""(\d+""") // かっこが閉じていない
tryRegex("""[a-z""") // 角かっこが閉じていない
tryRegex("""*abc""") // 繰り返しの記号が先頭にある
tryRegex("""a{2,1}""") // 回数の範囲が逆
tryRegex("""\""") // バックスラッシュで終わっている
tryRegex("""(?<1st>\d)""") // グループ名が数字で始まる
tryRegex("""\d+)""") // 閉じかっこだけがある
tryRegex("""\d{3}-\d{4}""") // 正しいパターン
}
--- (\d+ ---
Unclosed group near index 4
(\d+
description=Unclosed group index=4
--- [a-z ---
Unclosed character class near index 3
[a-z
^
description=Unclosed character class index=3
--- *abc ---
Dangling meta character '*' near index 0
*abc
^
description=Dangling meta character '*' index=0
--- a{2,1} ---
Illegal repetition range near index 5
a{2,1}
^
description=Illegal repetition range index=5
--- \ ---
Unescaped trailing backslash near index 1
\
description=Unescaped trailing backslash index=1
--- (?<1st>\d) ---
capturing group name does not start with a Latin letter near index 3
(?<1st>\d)
^
description=capturing group name does not start with a Latin letter index=3
--- \d+) ---
Unmatched closing ')' near index 2
\d+)
^
description=Unmatched closing ')' index=2
OK: \d{3}-\d{4}
| メッセージ | 原因 | 直し方 |
|---|---|---|
| Unclosed group | 丸かっこが閉じていない | 閉じかっこを足す。かっこを文字として探すなら \( |
| Unclosed character class | 角かっこが閉じていない | ] を足す。文字として探すなら \[ |
| Dangling meta character | 繰り返しの記号の前に対象が無い | 前に文字を置く。記号そのものなら \ を前に付ける |
| Illegal repetition range | {2,1} のように範囲が逆 |
小さい数を先に書く |
| Unescaped trailing backslash | パターンがバックスラッシュ1つで終わっている | \\ と2つ書く |
| capturing group name does not start with a Latin letter | グループ名が数字で始まっている | 英字で始まる名前にする |
| Unmatched closing ')' | 閉じかっこだけがある | 開きかっこを足すか \) にする |
利用者が入力した文字列からパターンを作る場合は、try / catch で PatternSyntaxException を受けるか、Regex.escape で文字そのものとして扱います。
応用:入力チェックとログの分解
// 何度も使う Regex はトップレベルや companion object に置いて1回だけ作る
private val POSTAL = Regex("""\d{3}-\d{4}""")
private val HEX_COLOR = Regex("""#[0-9a-fA-F]{6}""")
private val LOG_LINE = Regex("""(?<time>\d{2}:\d{2}:\d{2}) \[(?<level>[A-Z]+)] (?<msg>.*)""")
fun main() {
println(listOf("123-4567", "1234567", "123-45678").map { it to POSTAL.matches(it) })
println(listOf("#1a2B3c", "#12345", "#gggggg").map { it to HEX_COLOR.matches(it) })
val logs = listOf(
"12:00:01 [INFO] started",
"12:00:05 [ERROR] connection refused",
"壊れた行",
)
for (line in logs) {
val m = LOG_LINE.matchEntire(line)
if (m == null) {
println("形式が違う行: $line")
continue
}
println("${m.groups["level"]!!.value} @ ${m.groups["time"]!!.value}: ${m.groups["msg"]!!.value}")
}
// when と組み合わせる
fun kind(s: String) = when {
POSTAL.matches(s) -> "郵便番号"
HEX_COLOR.matches(s) -> "色コード"
else -> "その他"
}
println(listOf("123-4567", "#ffffff", "abc").map(::kind))
}
[(123-4567, true), (1234567, false), (123-45678, false)]
[(#1a2B3c, true), (#12345, false), (#gggggg, false)]
INFO @ 12:00:01: started
ERROR @ 12:00:05: connection refused
形式が違う行: 壊れた行
[郵便番号, 色コード, その他]
Regex のオブジェクトは作るときにパターンの解析が走ります。繰り返し使うパターンは、ループの中で毎回作らず、トップレベルの val や companion object に置いて使い回します。 matchEntire は「形式の確認」と「グループの取り出し」を1回で済ませられるので、1行ずつのログやコードの分解に向いています。
よくある質問
Q. matches と containsMatchIn はどう使い分けますか? A. 文字列全体が形式どおりかを調べるなら matches、どこかに含まれていればよいなら containsMatchIn です。入力チェックに containsMatchIn を使うと、前後に余分な文字があっても true になります。
Q. find と findAll の戻り値は何ですか?
A. find は最初の一致を表す MatchResult(無ければ null)、findAll は MatchResult の Sequence です。文字列のリストがほしいときは findAll(text).map { it.value }.toList() と書きます。
Q. Regex("...") と "...".toRegex() に違いはありますか? A. 同じパターンの Regex ができます。変数に入っている文字列から作るときは toRegex()、その場で書くときは Regex(...) と使い分けると読みやすくなります。
Q. 大文字と小文字を区別せずに探すには?
A. Regex("kotlin", RegexOption.IGNORE_CASE) と書くか、パターンの先頭に (?i) を付けます。複数のオプションは setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE) のように Set で渡します。
まとめ
- 全体一致は matches / matchEntire、部分一致は containsMatchIn / find / findAll。入力チェックには全体一致を使います。
- グループは groupValues(0 番が全体)・destructured(1 番から変数へ)・groups["name"](名前付き)の3通りで取り出せます。
- replace にはラムダを渡せます。置換後の文字列で $ を文字として使うときは
Regex.escapeReplacementかラムダが確実です。 - split で前後に空文字が出るときは trim() を先に行います。
- RegexOption は7種類。IGNORE_CASE・MULTILINE・DOT_MATCHES_ALL・COMMENTS がよく使われます。
- パターンは raw 文字列("""...""")で書くと、バックスラッシュを重ねずに済みます。
- 文法の誤りは PatternSyntaxException。メッセージの near index と ^ が位置を示します。
参考・出典
- Kotlin 標準ライブラリ API リファレンス Regex(各関数の定義・戻り値・対応バージョン): https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/-regex/
- Kotlin 標準ライブラリ API リファレンス RegexOption(オプションの説明と対象プラットフォーム): https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/-regex-option/
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Kotlin 正規表現 Regexの使い方 find・replace」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。