<Lua> 文字列関係の一部処理とフォーマット処理

Last modified: 2019-07-21

ここでは文字列に関係する一部の処理とフォーマット処理の扱いについてと、そのコード例を扱う。

解説

文字列の連結

文字列の連結は..という演算子を用いて行う。幾つかの他の言語では+という演算子で文字列の連結が行えるが、Luaの場合はこれが異なるので注意が必要。

$ lua -e "print('ABC' .. 'DEF' .. 'GH')"
ABCDEFGH

文字列型変数と長さについて

プログラム内で扱うデータは変数を用いることで名前を付けて読み書きでき、Luaでも変数は利用できる。

変数には扱うデータの種類によって型が存在するが、Luaの変数の型は内容によって決まり、文字列を入れた変数は文字列型という型になる。

この文字列型でメンバ関数len()を呼ぶことで、その文字列のバイト数が得られる。

$ lua -e "s = 'abcde'; print(s:len())"
5

半角英数のみの文字列が入っていればその文字数ともなるが、UTF-8エンコーディングで半角英数以外を含む文字列を変数に入れてlen()を呼んでも文字の数は数えることができない。

(UTF-8環境での実行結果)
$ lua -e "s = 'あいうえお'; print(s:len())"
15

Lua 5.3以上ではutf8.len()によってUTF-8エンコーディングの文字列としての文字数を数えることができる。

(UTF-8環境での実行結果)
$ lua5.3 -e "s = 'あいうえお'; print(utf8.len(s))"
5

文字列の繰り返しを出力

string.rep()関数を用いると、1番目の引数の文字列を2番目の引数の数だけ繰り返した文字列が戻り値として得られる。

3番目の引数として文字列を付けると、これが繰り返しの際の区切り文字になる。

(区切り文字列なし)
string.rep([繰り返したい文字列], [反復数])

(区切り文字列あり)
string.rep([繰り返したい文字列], [反復数], [区切り文字列])

string.rep()は繰り返したい文字列のメンバ関数rep()として用いることもでき、その場合の引数はstring.rep()の2番目からの引数を指定する。

(区切り文字列なし)
[繰り返したい文字列]:rep([反復数])

(区切り文字列あり)
[繰り返したい文字列]:rep([反復数], [区切り文字列])

注意点として、繰り返したい文字列の部分(:の左)が変数ではなく'"で囲まれた文字列定数(文字列リテラル)の場合、他の幾つかの言語とは異なり、それを丸括弧で囲む必要がある。例えば

('T_T'):rep(49)

は文法的に正しいが

'-_-':rep(18)

は文法エラーとなる。これ以外にも文字列定数のメンバ関数を呼ぶ場面はあるが、その場合も同様に丸括弧が必要。

フォーマット (書式整形) 処理

string.format()関数を用いると、書式を示す文字列とその中に含まれる値を指定して整形された文字列を戻り値として得ることができる。

例えば

  • 26という値(もしくはこの値の入った変数)
  • “今年は令和%d年です” という書式文字列

から “今年は令和26年です” という文字列が得られる。また、書式文字列内の指定の仕方によっては桁の表示などを細かく調整することもできる。

string.format()の1番目の引数の文字列は書式を示す文字列で、値が入る部分にはその形式に応じた記述が必要となる。値が入る場所の分だけ2番目からの引数で指定し、値が入る部分が2つあれば2番目と3番目の引数としてその値(もしくは値の入っている変数)を渡す。

string.format([フォーマット文字列], [値...])

このあたりの動作は基本的にはC言語のprintf()系関数と同様となるが、一部異なる部分もあるのでリファレンスのstring.format()の項目(日本語訳)を参照。

なお、string.format()もフォーマット文字列に対するメンバ関数format()として用いることもでき、その場合の引数は値部分のみとなる。

[フォーマット文字列]:format([値...])

コード例

下のコードは、プログラム(特にフォーマット関係)の挙動を色々な形で確かめる目的によって、意図的に記述の仕方が統一されていなかったり、値の表示形式が色々変わっていたりする。

[任意]ファイル名:002_strings-and-formatting.lua エンコーディング:UTF-8

#! /usr/bin/lua
-- -*- coding: utf-8 -*-

--[[--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
動作確認バージョン: 5.3, JIT2.1
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --]]

-----
----- 文字列とフォーマット
-----

-- string.rep()は指定文字列(1番目の引数)を指定回数(2番目の引数)繰り返したものが
-- 戻り値として得られる
-- 名前の由来は「repeat」と思われる
print(string.rep('-', 80))  -- 引数が複数ある場合は「,」で区切る

-- 文字列を変数に代入
x = 'おー'
-- 連結は「..」で行う(「+」ではない点に注意)
y = x .. 'えー' .. 'あー'  -- xには文字列「おー」が入っている
-- 連結した結果を表示
print(y)

-- string.rep()の別の書き方で、繰り返したい文字列のメンバ関数として呼び出す
print(('+-'):rep(40))  -- 引数は回数のみ・「'+-':rep」とは書けない

z = 'Lua'  -- 1 + 1 + 1 = 3バイト
-- 「string.format([フォーマット文字列], [値...])」を用いると
-- 値を含む文字列を指定された形式で作ることができる
-- C言語のprintf()系関数の要領で変換の仕方も基本的には同様
-- ただし一部異なる動作もあるのでリファレンスマニュアルも参照
-- 「[文字列変数]:len()」は文字列のバイト数を得る
print(string.format('半角英数文字列 "%s" のバイト数は "%d"', z, z:len()))

u = 'ルア!'  -- 3 + 3 + 3 = 9バイト
-- 「%4d」は3桁以下でも半角スペースを用いて強制的に4桁にして右に揃える
-- (「   1」「   2」「   3」 ... 「 998」「 999」「1000」)
print(string.format('UTF-8全角文字列 "%s" のバイト数は "%4d"', u, u:len()))
-- 下の行はLua 5.3以上の場合コメント解除して実行するとUTF-8での文字数が得られる
--print(string.format('UTF-8全角文字列 "%s" のUTF-8としての長さは "%4d"', u, utf8.len(u)))

-- string.format()の結果をprint()に渡すのを関数にする
-- 引数はstring.format()に丸投げしており、可変長の部分は「...」で表現される
-- 関数の定義について詳しくは別の例で扱う
function printf(...)
    print(string.format(...))
end

-- 上で定義した関数を呼び出す
-- 「%04d」は3桁以下でも「0」を用いて強制的に4桁にして右に揃える
m = 'Milkこぼれた!!'  -- 1 + 1 + 1 + 1 + 3 + 3 + 3 + 3 + 1 + 1 = 18バイト
printf('半角英数とUTF-8全角の混じった文字列 "%s" のバイト数は "%04d"', m, m:len())

-- string.rep()に3番目の引数を付けると区切り文字列になる
print(string.rep('--', 27, '*'))
--print(('--'):rep(27, '*'))  -- 別の書き方

-- 小数のフォーマット
-- 「.[数字]f」で小数点以下の表示桁数を調整
printf('ルート%dは %.8f ぐらい', 2, math.sqrt(2))  -- math.sqrt()は平方根計算関数
-- string.format()の代わりに
-- 「[フォーマット文字列]:format([値...])」という書き方もできる
print(('ルート%dは %012.8f ぐらい'):format(3, 3 ^ 0.5))  -- 3 ^ 0.5はルート3

-- 終了

下は実行例。UTF-8環境の端末シェルの中から動かす。

$ lua [002_strings-and-formatting.luaの場所]
--------------------------------------------------------------------------------
おーえーあー
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
半角英数文字列 "Lua" のバイト数は "3"
UTF-8全角文字列 "ルア!" のバイト数は "   9"
半角英数とUTF-8全角の混じった文字列 "Milkこぼれた!!" のバイト数は "0018"
--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--
ルート2は 1.41421356 ぐらい
ルート3は 001.73205081 ぐらい

コード中のutf8.len()の使用行の行頭の--を消してLua 5.3以上で実行した場合、出力に下の行が追加される。

UTF-8全角文字列 "ルア!" のUTF-8としての長さは "   3"
  • 使用したバージョン
    • Lua 5.3.3
    • LuaJIT 2.1.0 Beta 3