bio_img_japan-community

MATLAB ユーザーコミュニティー

MATLAB & Simulink ユーザーコミュニティー向け日本語ブログ

MATLAB で文字列処理、string 型のススメ!

皆さんこんにちは、トレーニングチームの遠藤です。このブログでは、「MATLAB と Simulink を繋ぐ」をテーマに、主に技術的な記事を書いています。

最近めっきり寒くなってきましたね。私は自宅から最寄り駅まで 15 分歩かなくてはならないので、毎日寒さに耐えながら帰り、自室の PC の GPU で暖を取る日々が続いています。

と、そんな冗談は置いておいて、今回は久々に技術記事の執筆ということで、少し MATLAB に寄った内容について書いていこうかと思います。今回のキーワードはズバリ、「文字列処理」です!

 

0. MATLAB で文字列処理

突然ですが MATLAB クイズです!

今、あなたは MATLAB でループ処理を実行しており、各ループの実行結果を “result1.mat”, “result2.mat”, …… というように連番の名前を付けて保存しようとしています。いったいどんなコードを書けばいいでしょうか?

………

……

実際にコードを書いてみると、連番のファイル名を用意するのが意外と曲者です。例えば以下のようなコードになるでしょうか。

for k = 1:10
    result = myFunc(k); % メイン処理
    fileName = ['result' num2str(k) '.mat']; % 連番ファイル名の作成
    save(fileName,'result');
end

num2str() 関数を使ってループ番号(数値)を文字列に直し、’result’ と ‘.mat’ に結合することでファイル名を作る、というやり方です。数値と文字を組み合わせる必要があるので、少し複雑なコードになっていますね。

 

……というのは、昔の MATLAB の話。今の MATLAB は、新しい文字列用のデータ型である string 型を使うことで、もっとシンプルなコードを書くことができます!

for k = 1:10
    result = myFunc(k); % メイン処理
    fileName = "result" + k + ".mat"; % 連番ファイル名の作成
    save(fileName,"result");
end

“result” と k と “.mat” を足し算でくっつけるだけ。このように、string 型を使うと、様々な文字列処理を直感的にわかりやすく実装することができます。

ということで、今回の記事では、この string 型の特徴やそれを使うメリットについて紹介していきたいと思います!

 

1. string 型とは?

string 型は、MATLAB R2016b から追加された、文字列データを扱うための新しいデータ型です。昔から MATLAB を使っている方は、文字列といえばシングルクォーテーション(’)を使った「char 型」がなじみ深いかと思いますが、string 型はダブルクォーテーション(”)を使って作成します。

txt1 = 'こんにちは';
txt2 = "こんにちは";

中身の文字列は同じ「こんにちは」、エディタ上の見た目も同じピンク(紫)色ですが、2 つの変数のデータ型は明確に区別されています。

 

2. char 型と string 型の違い

char 型と string 型はどちらも文字列データを扱うデータ型で、作り方も似ています。しかし、この 2 つのデータ型の性質は大きくことなります。わかりやすいようにこの2つのデータ型の違いを表にまとめてみました。

char 型 string 型
作り方 シングルクォーテーション ダブルクォーテーション
単一の文字列の扱い方 ベクトル スカラ
複数の文字列の扱い方 セル配列 ベクトル
結合方法 ベクトル結合 +演算子

作り方については既に説明した通りですので、それ以外の点について簡単に解説します。

 

①単一の文字列の扱い方

先ほど作った txt1, txt2 のサイズを length 関数で確認してみます。

>> length(txt1)

ans =

     5

>> length(txt2)

ans =

     1

txt1 は 5、txt2 は 1 となっています。char 型は文字列を「文字が結合したベクトル」として扱い、string 型は「1つのまとまった文字列」として扱っていることがわかります。

 

②複数の文字列の扱い方

char 型で複数の文字列をまとめる場合、セル配列を使用します。

>> txts1 = {'こんにちは','お元気ですか?'}

txts1 =

  1×2 の cell 配列

    {'こんにちは'}    {'お元気ですか?'}

それに対し、string 型はベクトル(string 配列)を使用します。

>> txts2 = ["こんにちは","お元気ですか?"]

txts2 = 

  1×2 の string 配列

    "こんにちは"    "お元気ですか?"

セル配列は色々なデータを1つにまとめることができて便利な反面、ベクトルに比べて演算がしづらいという欠点があり、ベクトルとして管理できるという点は明確なメリットとなります。この点については、次節の「string 型のメリット」で詳しく説明します。

 

③結合方法

char 型は文字列をベクトルとして扱っているので、文字列同士を結合する場合、通常のベクトルと同様に、大かっこを使って結合する必要があります。

>> txt1 = ['MAT' 'LAB']

txt1 =

    'MATLAB'

それに対し、string 型は + 演算子で結合することができます。

>> txt2 = "MAT"+"LAB"

txt2 = 

    "MATLAB"

大かっこで囲う書き方は結合する要素が増えるほどミスしやすいので、シンプルに足し算で繋いでいけるのはありがたいですね。なお、append 関数を使うとどちらのデータ型も結合できます。

 

このように、char 型と string 型は同じ文字列を扱うデータ型であってもその性質は大きく異なります。大雑把にまとめると、char 型は文字を一単位として、string 型は文字列を一単位として管理している、というようなイメージですね。

 

3. string 型のメリット

それでは、string 型の性質もなんとなく理解できたところで、ここからは文字列処理に string 型を使うメリットを確認していきましょう!

 

メリット1:数値との連結が簡単

前述の通り、string 型は + 演算子で結合することができますが、実はこれ、同じ文法で数値とも結合することができます

>> version = "R"+2025+"b" % 数字と文字を + で結合!

version = 

    "R2025b"

冒頭のクイズの解答でもこの文法を使っていましたね。char 型は数値と直接結合することができないため、num2str 関数で変換して結合する、という処理が必要になります。そのため、結合する数値が増えるほどコードが複雑になってしまいます。

>> version = ['R' num2str(2025) 'b Update' num2str(1)]

version =

    'R2025b Update1'

>> version = "R"+2025+"b Update"+1

version = 

    "R2025b Update1"

そのため、数値を文字列と結合する処理が頻出するようなプログラムの場合は、string 型を使うのがオススメです。

 

メリット2:ベクトル演算が使える

string 型は複数の文字列をベクトルで管理するため、MATLAB のベクトル演算の仕様を活用することができます

例えば、以下の苗字と名前を組み合わせ、3 x 3 = 9 通りのフルネームを作ろうとした場合、どのようなコードを書けばよいでしょうか?

苗字:田中、佐藤、鈴木
名前:一郎、二郎、三郎

 

char 型を使って素直にコードを書くと、以下のようなコードになるかと思います。

lastName = {'田中','佐藤','鈴木'};
firstName = {'一郎','二郎','三郎'};
fullName = cell(1,9);
idx = 1
for k = 1:3
    for n = 1:3
        fullName{idx} = [lastName{n} firstName{k}];
        idx = idx + 1;
    end
end

2重ループを回して1つずつ結合していく、というアプローチですね。コードそのものは単純でわかりやすいですが、これだけのために2重ループを回すのはちょっと大げさな気もします。

また、char 型の扱いに慣れている方は、以下のような cellfun 関数を使ったコードを思いつくかもしれません。

lastName = {'田中','佐藤','鈴木'};
firstName = {'一郎','二郎','三郎'};
fullName = cellfun(@(x) append(x,firstName),lastName,'UniformOutput',false);
fullName = [fullName{:}];

cellfun 関数で lastName の各要素に firstName を結合することで、9 パターンのフルネームを作成しています。さっきに比べてコードが短くなりましたが、今度は処理が複雑になったのであまり直感的ではないコードになってしまいました。

それではこれを string 型で書くとどうなるでしょうか?

lastName = ["田中","佐藤","鈴木"];
firstName = ["一郎";"二郎";"三郎"];
fullName = lastName+firstName;

なんと、足し算だけで作ることができてしまいます。

このコードのポイントは、lastName を横ベクトル、firstName を縦ベクトルで作っている点です。MATLAB には「縦ベクトルと横ベクトルを足し算しようとすると、それらをコピーして行列に拡張して演算を行う(暗黙的拡張)」という仕様があります。

参照:基本的な演算で互換性のある配列サイズ

string 型はベクトルであり、かつ足し算で結合を行いますので、この仕様を活用することができるのです。

前述の数字との連結機能と組み合わせれば、複数の日付データを作るときにも活用できますね!

>> dates = ((1:3)+"月")+((1:3)+"日")' % 1-3月と1-3日を結合

dates = 

  3×3 の string 配列

    "1月1日"    "2月1日"    "3月1日"
    "1月2日"    "2月2日"    "3月2日"
    "1月3日"    "2月3日"    "3月3日"

セル配列は主要な演算に対応していないので、char 型ではどうしても for ループや cellfun 関数が必要になってしまい、コードが複雑になりがちです。特に、今回のような複数文字列同士の結合を行いたい場合は、string 型を使うのがオススメです。

 

メリット3:pattern オブジェクトが使える(R2020b 以降)

例えば、以下の文章の中に含まれる MATLAB のバージョンをすべて取得しようと思った場合、どうすればよいでしょうか?

string 型は R2016b で導入された便利なデータ型です。実際、同僚の Robert は 2021 年に MATLAB のバージョンを R2021a に上げて以来、char 型を使わなくなってしまいました。

“R” を探すだけだと “Robert” もヒットしてしまいますし、数字を探すだけだと “2021 年” もヒットしてしまいます。バージョン情報だけを抽出したければ、「R から始まり、数字が 4 つ続き、a か b で終わる」というパターンを満たす文字列を探す必要があります。

通常、このような特定のパターンの文字列を探す場合、以下のような正規表現を活用したコードが必要となります。

>> chr = 'String 型は R2016b で導入された便利なデータ型です。実際、同僚の Robert は 2021 年に MATLAB のバージョンを R2021a に上げて以来、Char 型を使わなくなってしまいました。';
>> pattern = 'R\d{4}[ab]'; % 正規表現でパターンを表現
>> version = regexp(chr,pattern,'match')

version =

  1×2 の cell 配列

    {'R2016b'}    {'R2021a'}

正規表現とは、文字列のパターンを表現するための文法のようなものです(詳細はこちら)。今回は数字 4 つを “/d{4}”、a か b かを “[ab]” で表現し、それと一致する文字列を regexp 関数で抽出しています。ただ、正規表現は様々なルールがあるので、慣れるまでは自分が注目したい文字列パターンをどうやって表現すればいいか悩みがちです。

これに対し、R2020b から導入された pattern オブジェクト というものを使うと、もっと直感的にコードを書くことができます。

>> str = "string 型は R2016b で導入された便利なデータ型です。実際、同僚の Robert は 2021 年に MATLAB のバージョンを R2021a に上げて以来、Char 型を使わなくなってしまいました。";
>> pattern = "R"+digitsPattern(4)+characterListPattern("ab"); % pattern オブジェクトでパターンを表現
>> version = extract(str,pattern)

version = 

  2×1 の string 配列

    "R2016b"
    "R2021a"

正規表現の代わりに、digitsPatterncharacterListPattern といった pattern オブジェクトを使ってパターンを表現しています。コード自体は少し長くなっていますが、どのようなパターンを表しているかがわかりやすくなりました。

さらに、pattern オブジェクトを結合した文字列は pattern オブジェクトとして管理されますので、通常の文字列と見分けがつきやすい、というのも嬉しいポイントです。

中身を見ないでもこの変数がパターンを表していることがわかるので、コードの可読性向上に繋がります。

また、正規表現は regexp などの専用の関数と組み合わせて使用する必要がありますが、pattern オブジェクトは extract 関数や contains 関数、replace 関数など、通常の文字列処理で使う関数とそのまま組み合わせて使うことができます。そのため、特定の文字列を探す処理も、特定のパターンを探す処理も、全く同じ構造のコードで実装でき、コードの拡張性や再利用性に繋がります。

しかし、残念ながら、pattern オブジェクトは string 型としか結合することができません。そのため、無理やり char 型と結合しようとすると、

>> pattern = 'R'+digitsPattern(4)+characterListPattern('ab')

pattern = 

  pattern

  マッチング:

    "R" + digitsPattern(4) + characterListPattern("ab")

強制的に string 型に変換されてしまいます。一応そのまま char 型の文字列処理に使うことは可能ですが、char 型と string 型が混在するコードになって文法ミスのリスクが高くなりますので、pattern オブジェクトを使う予定の場合は string 型を使うのがよいかと思います。

なお、pattern オブジェクトはすべての正規表現を完璧にカバーしているわけではありませんので、複雑なパターンが必要になる場合は正規表現を使わなければならないケースもあります。そのような場合、regexpPattern を使うと正規表現の pattern オブジェクトを作ることができるので、通常の pattern オブジェクトで表現できるところは表現し、表現できない部分は正規表現で pattern オブジェクトを作り、それらを結合して 1 つのパターンを作る、というのもありかと思います。

 

4. char 型との使い分け

ここまで string 型のメリットを挙げてきましたが、もちろん char 型を使った方がよい場合もあります。特に、特定の位置の文字にアクセスするような処理が多い場合は、char 型を使う方がコードを書きやすいです。

前述の通り、char 型は文字列を文字のベクトルとして扱いますので、インデックス指定により簡単に文字にアクセスできます。

>> chr = 'ID:12345';
>> id = chr(4:end)

id =

    '12345'

string 型は文字列を 1 つの塊として扱っているため、特定の位置にアクセスしようと思ったら専用の関数が必要になります。

>> str = "ID:12345";
>> id = extractAfter(str,3)

id = 

    "12345"

他にも、以下のようなケースに該当する場合も、char 型を使うことが推奨されます。

・古いバージョンや関数との互換性が重要な場合

string 型は R2016b 以降のバージョンでしか使用することができません。それよりも古いバージョンの MATLAB でも使用する可能性のあるプログラムを作っている場合や、古いバージョンで作った関数を使用する場合は、互換性重視で char 型を使用するのがオススメです。

・メモリ効率を重視する場合

string 型に比べて char 型の方がメモリ消費が少ないので、大量の文字列を扱う場合は char 型を使う方がメモリを節約できます。

・文字コード処理を行う場合

char 関数により文字コードを対応する文字に変換できるため、文字コード系の処理を簡単に行うことができます。

・C 言語との連携を行う場合

文字配列(char*)を入力とする C 言語の関数を MATLAB で呼び出す場合、char 型を使用する必要があります。また、C 言語の関数から返ってくる文字配列も char 型です。そのため、C 言語の文字列処理系の関数を何度も使用するような場合は、文字列を char 型に統一した方が扱いやすくなります。

 

ただ、これらは少し状況が限定されているので、とりあえずは

基本的な文字列処理は string 型
文字単体が重要な場合は char 型

という大雑把なイメージを持った上で、自分が使う関数等との兼ね合いも考慮して使い分ける、というのがオススメです。

 

また、2025年9月より MathWorks から公開しているコーディングガイドライン上では、複数の文字列を扱う場合、char 型のセル配列よりも string 型の配列を使うことが推奨されていますので、「複数の文字列が出てきたら string 型!」と覚えてしまってもよいかもしれませんね。

 

5. まとめ

ということで、今回は string 型についてのお話でした。私も業務改善アプリの開発等で普段文字列処理を行っていますが、string 型に助けられる機会は非常に多いです。今まで char 型をずっと使ってきた方も、ぜひ一度 string 型を試してみてください!

|
  • print

コメント

コメントを残すには、ここ をクリックして MathWorks アカウントにサインインするか新しい MathWorks アカウントを作成します。