標準ライブラリ¶
Onionの標準ライブラリは、一般的な機能のための組み込みモジュールとインターフェースで構成されています。
モジュール一覧¶
| 領域 | モジュール |
|---|---|
| I/O・システム | IO(コンソール), Files(ファイル・パス), System, Proc(サブプロセス), Args(CLI), Http(HTTPクライアント) |
| コレクション | Colls(リスト: map/filter/fold, chunked/windowed, sumBy/maxBy), Iterables, Maps, Sets |
| テキスト | Strings(大小文字・分割・パディング・パース), Text(wrap/indent/table), Regex |
| 数値 | Math, OnionMath(双曲線関数, clamp, hypot, 範囲付きrandomInt), Stats(sum/average/median/stddev), Format(桁区切り・bytes・duration) |
| データ形式 | Json, Yaml, Csv, Config(ドット記法での設定値アクセス) |
| エンコード | Codec(base64/hex/url), Hash(md5/sha256/…) |
| 関数型 | Option, Result, Future, Outcome・Defect(外部データの読み取り) |
| 位置情報 | Origin(値がどのテキストのどこから来たか) |
| 境界 | Shape・Shapes(テキスト↔型付き値), Scalars |
| 日時・乱数 | DateTime, Rand(choice/shuffle/sample/uuid) |
| テスト・計測 | Assert, Timing |
ほとんどのヘルパーは静的な Module:: 呼び出しだけでなくメソッドチェインでも書けます——
コレクション(list.filter { ... }.map { ... }, m.mapValues { ... })、文字列
("s".capitalize())、ハッシュ・エンコード("pw".sha256(), "x".base64Encode())、
テキスト整形(text.wrap(40))、数値集計(nums.sum(), nums.average())、数値フォーマット
((1536L).bytes(), (21L).ordinal())。
IO モジュール¶
コンソール入出力操作。
IO::println¶
標準出力に改行付きで出力:
IO::print¶
改行なしで出力:
IO::readln¶
ユーザーから1行の入力を読み取り:
IO::readLine¶
標準入力から1行読み取り、入力の終端では null を返す。プロンプトなしの
IO::readln() はこのメソッドの別名:
IO::readAll¶
残りの標準入力全体を1つの文字列として読み取り:
フォーマット出力¶
エラー出力(stderr)¶
IO::eprint("warning: ")
IO::eprintln("disk almost full")
IO::eprintf("failed after %d retries\n", 3)
型安全な入力¶
1行を指定の型として読み取ってパースし、不正な入力なら例外を投げる。各メソッドには 先にプロンプトを表示するオーバーロードがある:
val age: Int = IO::readInt("Age: ")
val price: Long = IO::readLong("Price: ")
val ratio: Double = IO::readDouble("Ratio: ")
val ok: Boolean = IO::readBoolean("Continue? ") // true/yes/1、false/no/0 を受け付け
安全な入力¶
上記の型安全な読み取りと同様だが、不正な入力や入力終端では例外を投げず
null を返す:
val n: Int? = IO::tryReadInt("N: ")
val d: Double? = IO::tryReadDouble("D: ")
val l: Long? = IO::tryReadLong("L: ")
行単位の入出力¶
val lines: List = IO::readLines() // 入力の終端まで読み取り
IO::eachLine { line => IO::println(line) } // 残りの各行にコールバックを適用
IO::printLines(["a", "b", "c"]) // 1項目1行で出力
IO::printAll("a", "b", "c") // printLines の可変長引数版
ユーティリティ¶
Math モジュール¶
JavaのMathクラス経由の数学演算。
Math::random¶
0.0から1.0の乱数を生成:
Math::sqrt¶
平方根:
Math::pow¶
累乗:
Math::abs¶
絶対値:
Math::max / Math::min¶
最大値と最小値:
Math::floor / Math::ceil / Math::round¶
丸め処理:
val floor: Double = Math::floor(3.7) // 3.0
val ceil: Double = Math::ceil(3.2) // 4.0
val round: Long = Math::round(3.5) // 4
Math::sin / Math::cos / Math::tan¶
三角関数(ラジアン):
val sine: Double = Math::sin(Math::PI / 2) // 1.0
val cosine: Double = Math::cos(0.0) // 1.0
val tangent: Double = Math::tan(Math::PI / 4) // 1.0
Math Constants¶
OnionMath モジュール¶
JDKのMathとは別のonion.*数値モジュールで、双曲線関数、安全な丸め・クランプ、範囲付きの
乱数整数を提供します。標準ライブラリの他のモジュールと同様デフォルトでインポートされるため、
明示的なインポートは不要です。
OnionMath::sin / OnionMath::cos / OnionMath::tan / OnionMath::asin / OnionMath::acos / OnionMath::atan / OnionMath::atan2¶
三角関数と逆三角関数(ラジアン):
val sine: Double = OnionMath::sin(OnionMath::PI / 2) // 1.0
val angle: Double = OnionMath::atan2(1.0, 1.0) // pi/4
OnionMath::sinh / OnionMath::cosh / OnionMath::tanh¶
双曲線関数:
OnionMath::exp / OnionMath::log / OnionMath::log10¶
指数関数と対数関数:
val e2: Double = OnionMath::exp(1.0) // e
val l: Double = OnionMath::log(OnionMath::E) // 1.0
val l10: Double = OnionMath::log10(100.0) // 2.0
OnionMath::pow / OnionMath::sqrt / OnionMath::cbrt¶
累乗と平方根・立方根:
val cube: Double = OnionMath::pow(2.0, 3.0) // 8.0
val root: Double = OnionMath::sqrt(16.0) // 4.0
val croot: Double = OnionMath::cbrt(27.0) // 3.0
OnionMath::abs / OnionMath::absFloat / OnionMath::absInt / OnionMath::absLong¶
プリミティブ型ごとの絶対値:
val a1: Double = OnionMath::abs(-3.14)
val a2: Int = OnionMath::absInt(-10) // 10
val a3: Long = OnionMath::absLong(-10L) // 10
OnionMath::min / OnionMath::minInt / OnionMath::minLong / OnionMath::max / OnionMath::maxInt / OnionMath::maxLong¶
プリミティブ型ごとの最小値・最大値:
OnionMath::floor / OnionMath::ceil / OnionMath::round / OnionMath::roundFloat¶
丸め処理:
val f: Double = OnionMath::floor(3.7) // 3.0
val c: Double = OnionMath::ceil(3.2) // 4.0
val r: Long = OnionMath::round(3.5) // 4
val rf: Int = OnionMath::roundFloat(3.5f) // 4
OnionMath::random / OnionMath::randomInt¶
乱数生成。Math::randomと異なり、randomIntは範囲を直接指定でき、エフェクトチェッカーに
よってRandエフェクトとして追跡されます:
val r: Double = OnionMath::random() // [0.0, 1.0)
val n: Int = OnionMath::randomInt(1, 10) // [1, 10](両端含む)
OnionMath::signum / OnionMath::signumFloat¶
数値の符号(-1.0、0.0、または1.0):
OnionMath::toRadians / OnionMath::toDegrees¶
角度単位の変換:
val rad: Double = OnionMath::toRadians(180.0) // pi
val deg: Double = OnionMath::toDegrees(OnionMath::PI) // 180.0
OnionMath::clamp / OnionMath::clampInt¶
値を範囲内に収める:
val c1: Double = OnionMath::clamp(15.0, 0.0, 10.0) // 10.0
val c2: Int = OnionMath::clampInt(-5, 0, 10) // 0
OnionMath::hypot¶
オーバーフロー・アンダーフローを避けた斜辺の長さ:
OnionMath Constants¶
Origin¶
値がどのテキストのどこから来たかを表します。コンパイラが持つソース位置の、実行時版です。
12行目で失敗したと分かっているパーサが、null を返す代わりにそう言えるようになります。
source は自由形式です——ファイルパス、URL、"<stdin>"、"<literal>" など。行と列は
1始まりです。列が 0 の場合は「行までしか分からない」ことを意味します。行単位のパーサが
正直に報告できるのはそこまでだからです。
import { onion.Origin; }
val o = Origin::at("access.log", 12, 5)
println(o.describe()) // access.log:12:5
val lineOnly = Origin::atLine("data.json", 4)
println(lineOnly.describe()) // data.json:4
println(lineOnly.hasColumn()) // false
Origin::at / Origin::atLine / Origin::spanning¶
at(source, line, column) は1文字分、atLine(source, line) は列なしの行、
spanning(source, line, column, span) は span 文字分を表します。
origin.onLine / origin.inSource¶
文書を行単位でパースすると、各行のパース結果はその行を基準にした位置を報告します。
onLine はそれを文書全体の位置に持ち上げ、inSource は別のソースに付け替えます。
origin.describe¶
file:line:column、行しか分からない場合は file:line を返します。コンパイラもエディタも
既に解釈できる形式です。toString も同じ結果を返します。
Outcome と Defect¶
外部データを読んだ結果です。値か、あるいは読めなかった理由すべてを表します。
Defect は「1つの不具合」、Outcome[T] は「値、またはその一覧」です。
Defect は呼び出し側が実際に知りたい3点に答えます——テキストのどこか(origin、無い場合
もある)、値のどこか(path)、そして何を期待して何があったか。
import { onion.Outcome; onion.Defect; onion.Origin; }
val d = Defect::at(Origin::atLine("config.json", 4), "port", "Int", "\"http\"")
println(d.describe()) // config.json:4: port: expected Int, found "http"
val missing = Defect::of("name", "String", "absent")
println(missing.describe()) // name: expected String, found absent
なぜ Result ではないのか¶
zip のためです。Result はモナドで bind は短絡するため、最初の不正フィールドが残りを
隠してしまいます。3つのフィールドが同時に壊れているなら、1回で3件報告すべきです。
Ok(f) zip Ok(x) = Ok(f(x))
Bad(d1) zip Ok(_) = Bad(d1)
Ok(_) zip Bad(d2) = Bad(d2)
Bad(d1) zip Bad(d2) = Bad(d1 ++ d2) <- この型が存在する理由
val a: Outcome[JInteger] = Outcome::bad(Defect::of("x", "Int", "p"))
val b: Outcome[JInteger] = Outcome::bad(Defect::of("y", "Int", "q"))
println(a.zip(b) { p, q => p + q }.defects().size) // 1 ではなく 2
bind は短絡したままです——後続の計算が前の値に依存しうる以上、そうでなければなりません。
両方使えます。do[Outcome] は bind を使います。
まとめて読む¶
all は全部か無かで、全 defect を集約します。部分的な結果に価値がある場合——良い行が
意味を持つログファイルなど——は values と defects で両方を取れます。
val os: List[Outcome[JInteger]] =
[Outcome::ok(1), Outcome::bad(Defect::of("a", "Int", "x")), Outcome::ok(3)]
println(Outcome::values(os).size) // 2
println(Outcome::defects(os).size) // 1
println(Outcome::all(os).isOk()) // false
ネストや行単位の読み取り¶
under は各 defect の path に接頭辞を付け、onLine はある行を基準に報告された位置を
文書全体の位置に持ち上げます。
Shape¶
外部テキストと型付き値の、部分的かつ(可能なら)双方向の対応です。Shape[T] はテキストを
T として読み、対応が可逆なら書き戻せます。
import { onion.Shape; onion.Shapes; onion.Outcome; }
val r = pointShape.parse("3,4")
if r.isOk() { println(r.get()) }
println(pointShape.print(pt))
意図的に区別している2つの法則¶
L2 が破れるのはごく普通の理由です——"007" は正しい Int ですが、書き戻すと "7" になります。
L2 も満たす shape を lossless と呼び、これは稀で、lens が必要とするものです。多くの shape は
L1 のみで、どちらなのかを明言することが「可逆な言語」と「可逆だと主張する言語」の差です。
canPrint¶
すべての shape が書き戻せるわけではありません。\s+ を区切りに使う正規表現には一意な
書き戻し方が無いため read-only になり、canPrint() が print を呼ぶ前にそう伝えます——
メソッドが黙って存在しない、という形にはしません。
成分の失敗は蓄積する¶
"abc,def" から Int を2つ読むと defect は2件報告されます。最初の1件ではありません。
Outcome の蓄積する zip はそのためにあります。
Lossless shape と lens¶
L2 も満たす shape を lossless と呼びます——isLossless() がそれを伝え、
parseLossless(text[, origin]) は素の T の代わりに Lossless[T] を読みます:値と、
その周辺すべての Residue(コメント、空白、キーの順序、元の値の書き方)です。
printLossless(value, residue) はその residue を通して書き戻します——変更していない
部分はバイト単位で再現され、意図的に変更した値だけが書き直されます。Residue は
不透明な値で、生成した shape にだけ渡し戻してください。
Lossless[T] そのものが lens です:value()/residue() でペアを読み、
withValue(v) は residue を保ったまま値だけ差し替え、edit { v => ... } は更新を
値にフォーカスします。render() がテキストを再構成します:
val r = configShape.parseLossless(file"app.conf".text()).get()
val out = r.edit { v => v.copy(port = 9090) }.render()
// diff app.conf out -> 1行だけ変わる
Shapes::config と Shapes::yaml は、shape name = config / shape name = yaml の
糖衣構文の裏にある lossless shape を、Shape[T] の値として直接組み立てます。
コンビネータ¶
eachLine(text[, origin])— 1行ごとにOutcome[T]を返し、読めた行と読めなかった 行の defect の両方を保持します(Outcome::values/Outcome::defectsで分離できます)。 ログファイルのように大半の行が読めるケースなど、部分的な結果に意味がある場合はlines()よりこちらを使います。lines()— 1行1値、全部読めるか失敗するかのShape[List[T]]です。sepBy(separator)— リテラルな区切り文字で分割する、全部読めるか失敗するかのShape[List[T]]です。xmap(forward, backward)— 同型写像に沿って shape を運びます。printが黙って 壊れないよう、両方向の関数が必要です。orElse(other)— この shape、読めなければother。どちらも読めない場合は両方の defect を報告します。印字はこの shape で行います。
関数インターフェース¶
ラムダとクロージャのための組み込み関数型。f.call(args)の代わりにf(args)として呼び出せます。
Function0¶
パラメータなしの関数:
Function1¶
1パラメータの関数:
Function2¶
2パラメータの関数:
val add: Function2[Int, Int, Int] = (x: Int, y: Int) -> { return x + y; }
val result: Int = add.call(3, 7)
Function3 から Function10 まで¶
3〜10パラメータの関数も同じパターンです。
ラッパークラス¶
プリミティブ型に対応するJavaのラッパークラス(文脈によってはJ接頭辞でアクセス)。
JInteger¶
Integer操作:
val i: Int = JInteger::parseInt("42")
val s: String = JInteger::toString(42)
val max: Int = JInteger::MAX_VALUE
val min: Int = JInteger::MIN_VALUE
JLong¶
Long操作:
JDouble¶
Double操作:
JBoolean¶
Boolean操作:
よく使うJavaクラス¶
よく使われるJava標準ライブラリのクラス。
String¶
文字列操作(自動的に利用可能):
val text: String = "Hello, World!"
val upper: String = text.toUpperCase()
val lower: String = text.toLowerCase()
val length: Int = text.length()
val sub: String = text.substring(0, 5)
val contains: Boolean = text.contains("World")
val starts: Boolean = text.startsWith("Hello")
val ends: Boolean = text.endsWith("!")
StringBuilder¶
効率的な文字列構築:
import { java.lang.StringBuilder; }
val builder: StringBuilder = new StringBuilder()
builder.append("Hello")
builder.append(" ")
builder.append("World")
val result: String = builder.toString()
ArrayList¶
動的配列:
import { java.util.ArrayList; }
val list: ArrayList[String] = new ArrayList[String]
list.add("First")
list << "Second" // <<演算子を使用
val size: Int = list.size()
val item: Object = list.get(0)
list.remove(0)
val empty: Boolean = list.isEmpty()
HashMap¶
キーバリューマップ:
import { java.util.HashMap; }
val map: HashMap[String, String] = new HashMap[String, String]
map.put("key1", "value1")
map.put("key2", "value2")
val value: Object = map.get("key1")
val has: Boolean = map.containsKey("key1")
val size: Int = map.size()
File¶
ファイル操作:
import { java.io.File; }
val file: File = new File("data.txt")
val exists: Boolean = file.exists()
val isFile: Boolean = file.isFile()
val isDir: Boolean = file.isDirectory()
val name: String = file.getName()
val path: String = file.getPath()
val length: Long = file.length()
BufferedReader¶
テキストの読み取り:
import {
java.io.BufferedReader;
java.io.FileReader;
}
val reader: BufferedReader = new BufferedReader(
new FileReader("file.txt")
)
var line: String = null
while (line = reader.readLine()) != null {
IO::println(line)
}
reader.close()
BufferedWriter¶
テキストの書き込み:
import {
java.io.BufferedWriter;
java.io.FileWriter;
}
val writer: BufferedWriter = new BufferedWriter(
new FileWriter("output.txt")
)
writer.write("Hello, World!")
writer.newLine()
writer.close()
Rand モジュール¶
onion.Randによる乱数生成ユーティリティ。
Rand::nextInt / nextLong / nextDouble / nextBoolean¶
乱数を生成:
val randomInt: Int = Rand::nextInt() // ランダムなInt
val randomLong: Long = Rand::nextLong() // ランダムなLong
val randomDouble: Double = Rand::nextDouble() // 0.0から1.0
val randomBool: Boolean = Rand::nextBoolean() // ランダムなBoolean
Rand::nextInt(範囲指定)¶
範囲内の乱数整数を生成:
val dice: Int = Rand::nextInt(6) + 1 // 1から6
val percent: Int = Rand::nextInt(100) // 0から99
val d20: Int = Rand::nextInt(1, 21) // 1から20(min, 排他的max)
Rand::nextDouble(範囲指定)¶
val small: Double = Rand::nextDouble(10.0) // 0.0から10.0
val ranged: Double = Rand::nextDouble(1.0, 2.0) // 1.0から2.0
Rand::choice¶
リストからランダムに1要素を選ぶ:
Rand::shuffle¶
リストをその場でシャッフル:
import { java.util.ArrayList; }
val list: ArrayList[String] = new ArrayList[String]()
list.add("A")
list.add("B")
list.add("C")
Rand::shuffle(list) // その場でシャッフル
Rand::sample¶
リストから重複なくn個の要素をランダムに選ぶ:
val deck: List[String] = ["A", "B", "C", "D", "E"]
val hand: List[String] = Rand::sample(deck, 3) // 重複しない3枚
Rand::uuid¶
ランダムなUUID文字列を生成:
Assert モジュール¶
onion.Assertによるテストアサーション。失敗時にAssertionErrorをスロー。
基本アサーション¶
Assert::isTrue(x > 0)
Assert::isFalse(list.isEmpty())
Assert::equals(expected, actual)
Assert::notEquals(a, b)
Nullアサーション¶
明示的な失敗¶
Timing モジュール¶
onion.Timingによる時間計測ユーティリティ。
現在時刻の取得¶
val startNanos: Long = Timing::nanos() // 高精度 (System.nanoTime)
val startMillis: Long = Timing::millis() // 壁時計 (System.currentTimeMillis)
経過時間の計測¶
val start: Long = Timing::nanos()
// ... 何らかの処理 ...
val elapsedNs: Long = Timing::elapsedNanos(start) // ナノ秒での経過時間
val elapsedMs: Double = Timing::elapsedMs(start) // ミリ秒での経過時間(サブミリ秒精度のdouble)
val elapsedMillis: Long = Timing::elapsedMillis(start) // Timing::millis()起点のミリ秒での経過時間
時間のフォーマット¶
val nanos: Long = 1234567890L
val formatted: String = Timing::formatNanos(nanos) // "1.23s"
// 出力形式: "123ns", "45.67μs", "12.34ms", "1.23s"
val millis: Long = 125000L
val formattedMs: String = Timing::formatMillis(millis) // "2m5s"
// 出力形式: "500ms", "1.23s", "2m30s"
スリープ¶
関数実行時間の計測¶
// 実行時間を計測して表示し、結果を返す
val result: Int = Timing::measure(() -> { return expensiveOperation(); })
// 出力: "Elapsed: 123.45ms"
// 戻り値のない関数版
Timing::measureVoid(() -> { expensiveOperation(); })
// 出力: "Elapsed: 123.45ms"
Timing::measureVoid("task", () -> { expensiveOperation(); })
// 出力: "task: 123.45ms"
// 表示なしで実行時間(ナノ秒)を取得
val timeNanos: Long = Timing::time(() -> { return expensiveOperation(); })
Option モジュール¶
onion.Optionで提供。
Option::some(value)/Option::none()/Option::of(value)opt.getOrElse(defaultValue)/opt.orElseGet(() -> default)/opt.orNull()opt.orElse(otherOption)opt.map(f)/opt.flatMap(f)/opt.filter(predicate)opt.contains(value)/opt.exists(predicate)opt.fold(() -> ifEmpty, v -> ifPresent)— 単一の値へ畳み込むopt.toList()— 0個または1個の要素のリスト
Result モジュール¶
onion.Resultで提供。
Result::ok(value)/Result::err(error)Result::ofNullable(value, errorIfNull)/Result::trying(operation)res.map(f)/res.mapError(f)/res.flatMap(f)/res.toOption()res.getOrElse(default)/res.orElseGet(() -> default)/res.orNull()res.fold(e -> ifErr, v -> ifOk)— 単一の値へ畳み込むres.recover(e -> value)/res.recoverWith(e -> otherResult)—Errを回復res.exists(predicate)/res.toList()
Future モジュール¶
onion.Futureで提供。非同期計算を表現。
Futureの作成¶
// 値で完了済み
val done: Future[Int] = Future::successful(42)
// 失敗で完了済み
val fail: Future[Int] = Future::failed(new RuntimeException("error"))
// バックグラウンドスレッドで非同期実行
val async: Future[String] = Future::async(() -> { return compute(); })
// 例外処理付きの非同期実行
val safe: Future[Int] = Future::asyncThrowing(() -> {
return riskyOperation();
})
// 遅延
val delayed: Future[Void] = Future::delay(1000L) // 1秒
変換メソッド¶
val f: Future[Int] = Future::successful(10)
// 値を変換
f.map((x: Int) -> { return x * 2; }) // Future[Int] = 20
// 非同期操作をチェイン
f.flatMap((x: Int) -> { return Future::successful(x + 1); })
// フィルタ(述語が false なら失敗)
f.filter((x: Int) -> { return x > 0; })
// flatMap の別名(do記法が使用)
f.bind((x: Int) -> { return Future::successful(x); })
エラーハンドリング¶
val f: Future[Int] = Future::failed(new RuntimeException("oops"))
// 値で回復
f.recover((e: Throwable) -> { return 0; })
// 別の Future で回復
f.recoverWith((e: Throwable) -> { return Future::successful(42); })
// エラーを変換
f.mapError((e: Throwable) -> { return new CustomException(e); })
コールバック¶
val f: Future[String] = Future::async(() -> { return "result"; })
f.onSuccess((value: String) -> { IO::println(value); })
f.onFailure((error: Throwable) -> { IO::println(error); })
f.onComplete(
(value: String) -> { IO::println("ok: " + value); },
(error: Throwable) -> { IO::println("err: " + error); }
)
ブロッキング操作¶
val f: Future[Int] = Future::successful(42)
f.await() // ブロックして結果を取得(失敗時は例外)
f.awaitTimeout(5000L) // タイムアウト付きでブロック(ミリ秒)
f.getOrElse(0) // 結果を取得、失敗時はデフォルト値
ステータス照会¶
f.isCompleted() // 完了していれば true(成功・失敗いずれも)
f.isSuccess() // 成功で完了していれば true
f.isFailure() // エラーで完了していれば true
これらは非ブロッキングです——future の現在の状態を報告するだけなので、まだ実行中の
future は isSuccess() と isFailure() の両方が false を返します。結果を待ちたい場合は、
isFailure() をポーリングするのではなく await()/getOrElse()(あるいは
onSuccess/onFailure/recover)を使ってください。
Futureの結合¶
val f1: Future[Int] = Future::successful(1)
val f2: Future[Int] = Future::successful(2)
// タプルのような配列へまとめる
f1.zip(f2) // Future[List[Object]] = [1, 2]
// レース: 先に完了した方が勝つ
f1.race(f2)
// すべての完了を待つ
Future::all(f1, f2, f3) // Future[List[Object]] = [1, 2, 3]
// 最初に完了したもの
Future::first(f1, f2, f3)
変換¶
val f: Future[Int] = Future::successful(42)
f.toOption() // Option[Int] - Some(42) または None(ブロックする)
f.toResult() // Result[Int, Throwable](ブロックする)
f.underlying() // 相互運用のための Java CompletableFuture
Do記法サポート¶
Futureは順次非同期合成のためのdo記法で動作:
val result: Future[Int] = do[Future] {
x <- Future::async(() -> { return fetchA(); })
y <- Future::async(() -> { return fetchB(x); })
ret x + y
}
Json モジュール¶
JSON のパースとシリアライズ。中間表現は Java の Map / List / scalar(String / Long / Double / Boolean / null)です。
Json::parse / Json::stringify¶
val obj = Json::parse("{\"name\":\"ko\",\"age\":3}") // Object(実体は Map)
val name = Json::getString(obj, "name") // "ko"
val age = Json::getInt(obj, "age") // 3
val m = Json::object() // 空の Map
m.put("x", 1)
val text = Json::stringify(m) // {"x":1}
val a = Json::array() // 空の List(JSON 配列値の構築に使う)
getString / getInt / getLong / getDouble / getFloat / getBoolean / getShort / getByte でキーから型別に取得します(見つからない・型不一致のときは null)。
これらはボックス化された値を返すため、見つからない場合の null をそのまま非 null なプリミティブへ代入すると NullPointerException になります。getStringOr / getIntOr / getLongOr / getDoubleOr / getFloatOr / getBooleanOr(obj, key, default) はフォールバック値付きでプリミティブを返すので、キーが無くても NPE になりません:
val obj = Json::parse("{}")
Json::getIntOr(obj, "missing", 42) // 42(NPE にならない)
Json::getStringOr(obj, "name", "anon") // "anon"
Json::value(ナビゲート可能なラッパー)¶
Json::value(text) は [] でインデックスアクセスできるラッパー値を返します。オブジェクトのキーには文字列、
配列の要素には整数でアクセスでき、値の取り出しには asString() / asInt() / asLong() / asDouble() /
asBoolean() を使います:
キーが存在しない・添字が範囲外のときは null を保持する Value を返すので、途中の欠損があっても例外にはなりません
(末尾で asString() 等を呼ぶと null になります)。isNull() で null かどうか、size() で配列・オブジェクトの
要素数(それ以外は 0)を調べられ、raw() で内部表現(Map/List/scalar/null)を直接取り出せます。
Json::parseOrNull(json) は Json::parse(json) と同じですが、不正な入力に対して例外
Json.JsonParseException を投げる代わりに null を返します。パース失敗を別扱いのエラーではなく
単なる「値が無い」ケースとして扱いたいときに便利です:
Json::asObject(obj) と Json::asArray(obj) は素の Map/List 表現に対する型安全なキャストです。
実行時の型が一致していれば Map/List にキャストした値を、そうでなければ null を返します。
Json::get・Json::parse・Json::parseOrNull が Object を返した後、Map/List として
イテレートしたいときに使います:
val obj = Json::parse("{\"tags\": [\"a\", \"b\"]}")
val tags = Json::asArray(Json::get(obj, "tags")) // List。"tags" が配列でなければ null
Yaml モジュール¶
flat block mapping ドキュメント限定の YAML パースとシリアライズ(onion.Yaml)。
Json と同じ中間表現を共有しており(scalar は同じ Java 型にマップされる)、
derive!(Yaml) は derive!(Json) とまったく同じ toMap / fromMap の土台の上に
構築されています。
対象範囲: flat block mapping のみ(ネストした map、シーケンス、アンカーは非対応)。
Yaml::parse¶
YAML の flat block-mapping 文字列を LinkedHashMap にパースします:
val data = Yaml::parse("name: Alice\nage: 30\n")
// data は LinkedHashMap;scalar の型推論は Json::parse と同じ
scalar の型推論規則(Json と同一):
- "" または null → null
- true / false → Boolean
- 整数リテラル(-?\d+ にマッチ)→ Long
- 浮動小数点パターンや ./e/E を含む数値 → Double
- クォートされた "..." → String(エスケープ解除のみ、それ以上の変換なし)
- それ以外 → String
不正な入力に対しては Yaml.YamlParseException を投げます。derive!(Yaml) の
fromYaml はこれを捕捉して代わりに null を返します。
Yaml::stringify¶
Map(または scalar)を YAML の flat block-mapping 文字列にシリアライズします:
パースし直したときに誤読される可能性のある文字列値(:、#、改行を含む、または
数値・真偽値に見えるもの)は自動的にダブルクォートされます。数値と真偽値はそのまま
出力されます。Map のキーも同じ規則でクォートされます — : や前後の空白を含む
キーは key: value の区切りと衝突しないようダブルクォートされます。
round-trip の保証¶
Yaml::parse が生成した任意の Map について、Yaml::parse(Yaml::stringify(m)) は
等しい map を返します。同様に、derive!(Yaml) を付けたレコードでは、scalar 成分の
みを持つすべての値について fromYaml(toYaml(v)) == v が成り立ちます。
derive!(Yaml) の利用¶
derive!(Yaml) は scalar 成分のみを持つ任意のレコードに対して fromYaml と
toYaml を合成します。
record ServerConfig(host: String, port: Int, debug: Boolean) derive!(Yaml)
val cfg = new ServerConfig("localhost", 8080, false)
val yaml = ServerConfig::toYaml(cfg)
// "host: localhost\nport: 8080\ndebug: false\n"
val cfg2 = ServerConfig::fromYaml(yaml) // ServerConfig? — パース/変換失敗時は null
derive!(Json, Yaml) も有効です。両フォーマットは内部の toMap / fromMap を
共有するため、重複はありません:
record User(name: String, age: Int) derive!(Json, Yaml)
val u = new User("ko", 3)
val viaJson = User::fromJson(User::toJson(u)) // == u
val viaYaml = User::fromYaml(User::toYaml(u)) // == u
Config モジュール¶
パース済み JSON に対するドット記法アクセスと設定読み込み(onion.Config)。内部では Json::parse をそのまま使うので、object / array / scalar の形は Json と同じです。YAML や .env 形式には対応せず、あくまで JSON とドット区切りパス、環境変数によるオーバーライドを提供します。
val config = Config::loadJson("config.json") // ファイルを読んでパース
val config2 = Config::parseJson("{\"port\": 8080}") // JSON 文字列を直接パース
Config::get(config, "database.host") // 生の値、見つからなければ null
Config::getString(config, "database.host", "localhost")
Config::getInt(config, "database.port", 5432)
Config::getLong(config, "database.maxConnections", 10L)
Config::getDouble(config, "database.timeout", 30.0)
Config::getBoolean(config, "database.ssl", false)
パスはドット区切りで、object と array の両方をたどれます。数字のセグメントは array のインデックスとして扱われます:
val config = Config::parseJson("{\"users\": [{\"name\": \"Alice\"}, {\"name\": \"Bob\"}]}")
Config::getString(config, "users.0.name", "unknown") // "Alice"
キーが見つからない場合・array の添字が範囲外の場合・値を要求された型へ変換できない場合は、例外を投げず指定したデフォルト値にフォールバックします。数値系のゲッターは JSON の数値だけでなく数値文字列も受け付けます。hasPath はデフォルト値なしで存在確認だけ行います:
環境変数へのアクセスも用意されています。getEnv はそのまま環境変数を読み、getWithEnvOverride は設定パスを読みつつ、対応する環境変数がセットされていればそちらを優先します(デプロイ時に設定ファイルの値を上書きするのに便利です):
Config::getEnv("PORT", "3000")
Config::getWithEnvOverride(config, "database.host", "DB_HOST", "localhost")
Strings モジュール¶
文字列ユーティリティ(onion.Strings、自動 import):
Strings::split("a,b,c", ",") // List[String] ["a","b","c"]
Strings::splitRegex("a1b2c", "[0-9]") // List[String] ["a","b","c"]
Strings::join(parts, "-") // 配列・List どちらも可
Strings::upper(s) / Strings::lower(s) / Strings::trim(s)
Strings::replace(s, "a", "b") / Strings::replaceRegex(s, "[0-9]+", "#")
Strings::startsWith(s, p) / Strings::endsWith(s, p) / Strings::contains(s, sub)
Strings::padLeft(s, 8, '0') / Strings::padRight(s, 8, ' ') / Strings::repeat(s, 3)
大文字小文字と検査のヘルパー:
Strings::capitalize("hello") // "Hello"
Strings::decapitalize("Hello") // "hello"
Strings::capitalizeWords("a b c") // "A B C"
Strings::containsIgnoreCase(s, sub) / Strings::equalsIgnoreCase(a, b)
Strings::count("banana", "a") // 3
Strings::isEmpty("") / Strings::isBlank(" ") // true / true
Strings::reverse("abc") // "cba"
Strings::lines("a\nb\r\nc") // List[String] ["a","b","c"]
Strings::removePrefix("unhappy", "un") // "happy"
Strings::removeSuffix("running", "ing") // "runn"
Strings::truncate("hello world", 8, "...") // "hello..."
Strings::center("hi", 6, '*') // "**hi**"
Strings::ifBlank(" ", "default") // "default"
Strings::words(" a b c ") // List[String] ["a","b","c"]
Strings::chars("abc") // List ["a","b","c"]
Strings::substring("hello", 1) / Strings::substring("hello", 1, 3) // "ello" / "el"
Strings::indexOf("hello", "l") / Strings::lastIndexOf("hello", "l") // 2 / 3
// null 安全なパース(例外を投げずに null/フォールバックを返す)
Strings::toIntOrNull("42") / Strings::toLongOrNull("100") / Strings::toDoubleOrNull("3.14")
Strings::toIntOr("nope", 0) // 0
Maps モジュール¶
Map ユーティリティ(onion.Maps)。結果 Map は挿入順を保持(LinkedHashMap)。
val m: Map[String, Int] = Maps::newMap()
Maps::getOrDefault(m, "a", 0) // あればその値、無ければデフォルト
Maps::getOrElse(m, "x", () -> compute()) // 遅延デフォルト
Maps::keys(m) / Maps::values(m) // 順序を保ったリスト
Maps::mapValues(m, (v: Int) -> v * 2) / Maps::mapKeys(m, (k: String) -> k.toUpperCase())
Maps::filterValues(m, (v: Int) -> v > 0) / Maps::filterKeys(m, (k: String) -> k.startsWith("a"))
Maps::filter(m, (k: String, v: Int) -> v > 0) // キー+値の述語
Maps::invert(m) // キーと値を入れ替え
Maps::toList(m, (k: String, v: Int) -> k + "=" + v) // エントリ -> List
Maps::forEach(m, (k: String, v: Int) -> println(k))
Maps::count(m, p) / Maps::anyEntry(m, p) / Maps::allEntries(m, p)
Maps::groupBy(items, keyOf) // Map[K, List]
Maps::countBy(items, keyOf) // 頻度 Map[K, Integer]
val merged = Maps::merge(a, b) // 衝突時は b が優先
Maps::mergeWith(a, b, (x: Int, y: Int) -> x + y) // 衝突を結合
Maps::update(m, "a", (v: Int) -> v + 1) // 関数的更新
Sets モジュール¶
Set ユーティリティ(onion.Sets)。結果 Set は挿入順を保持し、集合演算は null 安全。
Sets::of(1, 2, 3) / Sets::newSet[Int]() / Sets::fromList([1, 1, 2]) / Sets::toList(a)
Sets::union(a, b) / Sets::intersection(a, b) / Sets::difference(a, b)
Sets::symmetricDifference(a, b) // どちらか一方だけに含まれる
Sets::containsAll(a, b) // a が b の要素をすべて含む
Sets::isSubsetOf(a, b) / Sets::isSupersetOf(a, b) / Sets::isDisjoint(a, b)
Sets::map(a, f) / Sets::filter(a, p) / Sets::find(a, p)
Sets::forEach(a, (x: Int) -> println(x))
Sets::count(a, p) / Sets::any(a, p) / Sets::all(a, p)
Hash モジュール¶
暗号学的ハッシュ・チェックサム(onion.Hash)。文字列の UTF-8 バイトをハッシュ化し、小文字 hex のダイジェストを返します。
Hash::sha256("password") // 64文字 hex
Hash::sha512(text) // 128文字 hex
Hash::md5(text) / Hash::sha1(text) // チェックサム・互換用(衝突耐性なし)
Codec モジュール¶
テキストのエンコード・デコード(onion.Codec): Base64・hex・URL/パーセント形式。
val enc = Codec::base64Encode("Hello") // "SGVsbG8="
Codec::base64Decode(enc) // "Hello"
Codec::hexEncode("Hi") / Codec::hexDecode("4869")
Codec::urlEncode("a b&c") / Codec::urlDecode(s)
Stats モジュール¶
数値リストの集計(onion.Stats)。汎用集計は List[Int]/List[Long]/List[Double] を受け付け倍精度で計算。sumInt/sumLong は整数精度を保持。
val xs: List[Int] = [10, 20, 30, 40]
Stats::sum(xs) // 100.0 Stats::sumInt(xs) // 100
Stats::average(xs) // 25.0 Stats::median(xs) // 25.0
Stats::min(xs) / Stats::max(xs) // 10.0 / 40.0
Stats::variance(xs) / Stats::stddev(xs)
メソッド呼び出しの形でも使えます(実際のコードではこちらが自然です)。ただし
メソッド形式も同じく倍精度なので、Int のリストでも合計は Double になります。
Int で受け取りたい場合は Stats::sumInt を使ってください。
val xs: List[Int] = [10, 20, 30, 40]
xs.sum() // 100.0 (Double: 汎用集計)
Stats::sumInt(xs) // 100 (Int)
Int を返す sum() のオーバーロードが無いのは型消去のためです。実行時には要素型が
消えるので、sum(List[Int]) と sum(List[Double]) は同じ JVM シグネチャになります。
Format モジュール¶
locale 非依存の人間可読フォーマット(onion.Format)——桁区切り・小数・サイズ・時間。
Format::integer(1234567) // "1,234,567"
Format::number(1234.5678, 2) // "1,234.57"
Format::fixed(3.14159, 2) // "3.14"
Format::percent(0.756, 1) // "75.6%"
Format::bytes(1536) // "1.5 KB"(1024基準)
Format::duration(3661) // "1h 1m 1s"
Format::ordinal(21) // "21st"
Text モジュール¶
コンソールのテキストレイアウト(onion.Text)——折返し・インデント・整列テーブル。
Text::wrap("長い文章 ...", 40) // 折り返した行のリスト
Text::indent("a\nb", "> ") // "> a\n> b"
Text::dedent(" a\n b") // "a\nb"
Text::table([["Name", "Dept"], ["Alice", "Eng"], ["Bob", "Sales"]])
// Name Dept
// Alice Eng
// Bob Sales
System モジュール¶
Java の System クラスを介したシステムレベル操作へのアクセス。
System::out¶
標準出力ストリーム:
System::in¶
標準入力ストリーム:
import {
java.io.BufferedReader;
java.io.InputStreamReader;
}
val reader: BufferedReader = new BufferedReader(
new InputStreamReader(System::in)
)
System::currentTimeMillis¶
現在時刻をミリ秒で取得:
System::getProperty¶
システムプロパティを取得:
val os: String = System::getProperty("os.name")
val user: String = System::getProperty("user.name")
val home: String = System::getProperty("user.home")
System::exit¶
プログラムを終了:
Iterables モジュール¶
onion.Iterables(Java インターフェース)で提供。
コレクションや配列向けのイテレーションユーティリティ:
Iterables::map(list|iterable|set, f)Iterables::mapMap(map, f)- 各Map.Entryをfで変換した新しいMapを返すIterables::toList(iterable)- 任意のIterable(範囲を含む)をListに実体化するIterables::filter(list|iterable, predicate)Iterables::foldl(iterable, init, f)Iterables::reduce(list, initial, reducer)Iterables::exists(iterable, predicate)Iterables::forAll(iterable, predicate)Iterables::listOf(elements...)Iterables::newList(size)-size個分の容量を確保した空のListIterables::first(list)/Iterables::last(list)- リストが空ならnullIterables::reverse(list)Iterables::take(list, n)/Iterables::drop(list, n)Iterables::sort(list, comparator)/Iterables::sort(list)- 後者は要素がComparableであることが必要
Files モジュール¶
ファイル I/O(onion.Files):
Files::readText("path.txt") // ファイル全体を String として
Files::readLines("path.txt") // List[String]
Files::writeText("out.txt", content)
Files::writeLines("out.txt", lines) // List[String] を1行ずつ書き込む
Files::appendText("out.txt", content) // 追記。ファイルが無ければ新規作成
Files::readBytes(path) / Files::writeBytes(path, bytes)
Files::list("dir") // エントリ名の List
Files::listFiles("dir") // java.io.File エントリの List
Files::glob("dir", "*.on") // glob にマッチしたエントリ名
Files::delete(path) / Files::exists(path)
Files::isFile(path) / Files::isDirectory(path)
Files::mkdirs(path) // ディレクトリと不足する親ディレクトリを作成
Files::size(path) // Long。バイト数(存在しなければ0)
Files::copy(src, dst) // dst が既にあれば置き換える
Files::move(src, dst) // 移動(リネーム)。dst が既にあれば置き換える
Files::copyDir(src, dst) // ディレクトリを再帰的にコピー
パス操作ヘルパー——ファイル名・親ディレクトリ・結合・拡張子:
Files::getFileName("a/b/c.txt") // "c.txt"
Files::getParent("a/b/c.txt") // "a/b"
Files::getAbsolutePath("a/b/c.txt") // カレントディレクトリ基準の絶対パス
Files::joinPath("a/b", "c.txt") // "a/b/c.txt"
Files::ext("report.txt") // "txt"(拡張子。予約語を避けた名前)
Files::stem("report.txt") // "report"
Files::withExtension("report.txt", "md") // "report.md"
Csv モジュール¶
RFC 4180 準拠の自己完結型 CSV パース・シリアライズ(onion.Csv、自動インポート済み)——引用フィールド・カンマ/改行を含む値・二重引用符に対応。
val rows = Csv::parse(text) // List of List of String
val recs = Csv::parseWithHeader(text) // List of Map(ヘッダー -> 値)
Csv::column(rows, 0) // 位置指定で1列取得
Csv::columnByName(recs, "age") // ヘッダー名で1列取得
val out = Csv::stringify(rows) // rows -> CSV テキスト
val out2 = Csv::stringifyWithHeader(recs) // records -> CSV(parseWithHeader の逆)
Proc モジュール¶
スクリプト向けのプロセス実行(onion.Proc):
val r = Proc::capture("git", "status") // r.status() / r.stdout() / r.stderr() / r.succeeded()
Proc::run("ls", "-la") // stdout を String で取得(失敗時は例外)
Proc::exec("make", "build") // 終了コード、出力はそのまま素通し
Proc::captureIn("/tmp", "ls") // ...In 系は作業ディレクトリを指定
Args モジュール¶
コマンドライン引数のパース(onion.Args):
val parsed = Args::parse(args)
parsed.flag("verbose") // --verbose
parsed.option("out", "a.out") // --out path(デフォルト値付き)
parsed.intOption("level", 3)
parsed.positional() // オプション以外の引数の List
Colls モジュール¶
コレクションのファクトリとパイプライン(onion.Colls):
Colls::listOf("a", "b", "c") // 不変の List
Colls::mutableListOf(1, 2, 3) // ArrayList
Colls::range(0, 5) // List [0,1,2,3,4]
Colls::sortedBy(people) { p => p.age() }
// map/filter/reduce/fold のパイプラインは List/Iterable/配列の拡張メソッド:
// xs.map { x => x * 2 }.filter { x => x > 0 }
バッチ化・ウィンドウ化・セレクタ集計¶
これらも Colls:: の静的呼び出しとして、また Colls の他のメソッドと同様に
パイプラインとして連結できる List の拡張メソッドとして利用できる:
xs.chunked(3) // [[1,2,3],[4,5,6],[7]] - 最大3件のバッチ、最後は少なくなることがある
xs.windowed(3) // [[1,2,3],[2,3,4],[3,4,5]] - 1要素ずつスライドする窓
ps.sumBy((p) -> p.age()) // Double - 各要素にセレクタを適用した合計
ps.averageBy((p) -> p.age()) // Double - セレクタの平均、空なら0.0
ps.maxBy((p) -> p.age()) // セレクタの値が最大の要素、空ならnull
ps.minBy((p) -> p.age()) // セレクタの値が最小の要素、空ならnull
xs.chunked(2).map { b => (b as List).size() } // 他のパイプライン段と同様に連結できる
Http¶
HTTPクライアントユーティリティ(Java 11+ の HttpClient を使用)。
GET リクエスト¶
POST リクエスト¶
Http::post(url, body): String
Http::postJson(url, jsonBody): String // Content-Type: application/json を設定
Http::post(url, body, headers): String // headers は get と同じ
Response オブジェクト¶
Http::getResponse(url): Response // ボディだけでなく status/body/headers を返す
Http::postResponse(url, body): Response
Response は status: Int、body: String、headers: List のフィールドと、
isOk(): Boolean(2xx)・isError(): Boolean(4xx/5xx)のヘルパーを持つ。
ボディだけでなくステータスコードやヘッダーが必要なときに使う。
その他のメソッド¶
URL ユーティリティ¶
Http::encodeUrl(str): String
Http::decodeUrl(str): String
Http::buildQuery(params): String // params: キーと値を交互に並べる
Http::buildUrl(baseUrl, params): String // "?"/"&" + buildQuery(params) を付加
例¶
val response: String = Http::get("https://api.example.com/data");
val data: Object = Json::parse(response);
val postResponse: String = Http::postJson(
"https://api.example.com/users",
"{\"name\": \"Bob\"}"
);
DateTime¶
エポックミリ秒を使った日時ユーティリティ。
現在時刻¶
DateTime::now(): Long // 現在のエポックミリ秒
DateTime::nowString(): String // ISO 形式(ローカルタイムゾーン)
DateTime::nowString(pattern): String
パース¶
フォーマット¶
構成要素¶
DateTime::year(epochMillis): Int
DateTime::month(epochMillis): Int // 1-12
DateTime::day(epochMillis): Int // 1-31
DateTime::hour(epochMillis): Int // 0-23
DateTime::minute(epochMillis): Int // 0-59
DateTime::second(epochMillis): Int // 0-59
DateTime::dayOfWeek(epochMillis): Int // 1=月曜, 7=日曜
DateTime::dayOfYear(epochMillis): Int // 1-366
演算¶
DateTime::addDays(epochMillis, days): Long
DateTime::addHours(epochMillis, hours): Long
DateTime::addMinutes(epochMillis, minutes): Long
DateTime::addSeconds(epochMillis, seconds): Long
DateTime::addMonths(epochMillis, months): Long
DateTime::addYears(epochMillis, years): Long
比較¶
DateTime::diff(time1, time2): Long // ミリ秒単位の差分
DateTime::diffDays(time1, time2): Int
DateTime::diffHours(time1, time2): Long // hours / minutes / seconds は整数値
DateTime::diffMinutes(time1, time2): Long
DateTime::diffSeconds(time1, time2): Long
DateTime::isBefore(time1, time2): Boolean
DateTime::isAfter(time1, time2): Boolean
DateTime::dayName(epochMillis): String // "Friday"(英語、ロケール非依存)
DateTime::monthName(epochMillis): String // "March"
ファクトリ¶
DateTime::of(year, month, day): Long
DateTime::of(year, month, day, hour, minute, second): Long
DateTime::startOfDay(epochMillis): Long
DateTime::endOfDay(epochMillis): Long
例¶
val now: Long = DateTime::now();
IO::println("今日: " + DateTime::format(now, "yyyy-MM-dd"));
val tomorrow: Long = DateTime::addDays(now, 1);
IO::println("明日: " + DateTime::format(tomorrow));
val birthday: Long = DateTime::of(1990, 5, 15);
val age: Int = DateTime::diffDays(now, birthday) / 365;
Regex¶
正規表現ユーティリティ。
マッチング¶
Regex::matches(input, pattern): Boolean // 文字列全体がマッチ
Regex::find(input, pattern): Boolean // どこかにパターンが見つかる
抽出¶
Regex::findAll(input, pattern): List[String]
Regex::findFirst(input, pattern): String
Regex::groups(input, pattern): List[String] // 最初のマッチのグループ
Regex::groupsAll(input, pattern): List[List[String]] // 全マッチのグループ
置換¶
Regex::replace(input, pattern, replacement): String
Regex::replaceFirst(input, pattern, replacement): String
分割¶
ユーティリティ¶
Pattern リテラルのオーバーロード¶
re"..." リテラルは String ではなく java.util.regex.Pattern にコンパイルされます。
上記のマッチング/抽出/置換/分割の各メソッドには、コンパイル済み Pattern を直接
受け取るオーバーロードも用意されており、re"..." リテラルを String パターンを
経由せずそのまま渡せます:
Regex::matches(input, pattern: Pattern): Boolean
Regex::find(input, pattern: Pattern): Boolean
Regex::findAll(input, pattern: Pattern): List[String]
Regex::findFirst(input, pattern: Pattern): String
Regex::groups(input, pattern: Pattern): List[String]
Regex::groupsAll(input, pattern: Pattern): List[List[String]]
Regex::replace(input, pattern: Pattern, replacement): String
Regex::replaceFirst(input, pattern: Pattern, replacement): String
Regex::split(input, pattern: Pattern): List[String]
Regex::split(input, pattern: Pattern, limit): List[String]
例¶
val text: String = "Email: alice@example.com, bob@test.org";
val emails: List[String] = Regex::findAll(text, "[\\w.]+@[\\w.]+");
// ["alice@example.com", "bob@test.org"]
val masked: String = Regex::replace(text, "@[\\w.]+", "@***");
// "Email: alice@***, bob@***"
if (Regex::matches("hello123", "[a-z]+\\d+")) {
IO::println("パターンマッチ!");
}
次のステップ¶
- 基本構文 - 言語構文の詳細