1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【C言語】glib2.0を使ってみた〜正規表現〜

Posted at

はじめに

C言語でアプリケーションを作成するとき、入出力の基本的な処理からコーディングするのは面倒ですし、バグの温床のなりえます。
良い解決策がないか調べたところ、glib2.0というライブラリが

  • インストール・利用の容易さ
  • 多機能
  • ライセンス

という観点で、良さそうであると思いました。
一方、ネット上にあまり情報がなく、公式ドキュメントもわかりにくいということもあり、本記事にて基本的な使い方を紹介したいと思います。

今回は、正規表現について記載します。

動作環境

本記事は、下記の環境で動作を確認しています。

  • Ubuntu18.04
  • gcc

インストール手順

下記コマンドでglib2.0一式をインストールすることができます。
Ubuntu18.04の場合、バージョン2.56.4が入るようです。

sudo apt install libglib2.0-dev

使用例

本記事では、glibを用いた正規表現の基本的な使い方として下記3つの使用例を示します。
なお、本記事では正規表現の説明は省略させていただきますので、他の詳細な解説記事を参考にしていただければと思います。

  • 文字列抽出
  • 文字列置換
  • 名前つきグループによる文字列抽出

文字列抽出

まず基本的な文字列抽出の使用例を示します。
操作の流れとしては、

  1. g_regex_new関数で正規表現のコンパイルパターンオブジェクトを作成
  2. g_regex_match関数で入力文字列がコンパイルパターンにマッチするか判定
  3. マッチしたら、g_match_info_matches関数とg_match_info_next関数でイテレーションしながら、マッチした文字列を取得する

という流れになります。

下記に示すのは、Ichiro Suzuki, Satoshi Tanaka, Miwako Nakagawa, Keiko Suzuki\nという文字列から、スズキが名字の氏名を抽出するサンプルソースです。

main.c
#include <glib.h>

int main()
{
    gchar *str = "Ichiro Suzuki, Satoshi Tanaka, Miwako Nakagawa, Keiko Suzuki\n";
    //スズキが名字の名前パターンを作成
    gchar *pattern = "[A-z]+ Suzuki";

    GRegex *regex;
    GMatchInfo *match_info;
    GError *err = NULL;
 
    regex = g_regex_new(pattern, 0, 0, NULL);
    
    if (TRUE == g_regex_match(regex, str, 0, &match_info)) {
        g_print("str is matched.\n");

        while (g_match_info_matches(match_info)) {
            gchar *word = g_match_info_fetch(match_info, 0);
            g_print("Found: %s\n", word);
            g_free(word);
            g_match_info_next(match_info, &err);
        }
        if (NULL != err) {
            g_print("match error. msg=%s\n", err->message);
            g_error_free(err);
        }
    } else {
        g_print("str is not matched.\n");
    }

    //開放処理
    //g_regex_matchの結果がFALSEの場合も、match_infoはNULLではなくなるらしく、開放処理が必要
    g_match_info_free(match_info);
    g_regex_unref(regex);

    return 0;
}

下記のコマンドでコンパイルを行うことができます。

gcc main.c -o main `pkg-config --cflags --libs glib-2.0`

下記のコマンドで実行します。入力文字列の中から、スズキが名字の氏名を抽出することができました。

./main
str is matched.
Found: Ichiro Suzuki
Found: Keiko Suzuki

文字列置換

次に文字列置換の使用例を示します。
文字列置換にはg_regex_replace関数を使います。
下記に示すのは、mac1=00:11:22:aa:bb:cc, mac2=55:44:33:22:11:00,という文字列に対し、MACアドレスの部分をxxxに置換するサンプルソースです。

main.c
#include <glib.h>

int main()
{
    gchar *str = "mac1=00:11:22:aa:bb:cc, mac2=55:44:33:22:11:00,";
    //MACアドレスのパターンを作成
    gchar *pattern = "([0-9A-Fa-f]{2}(:[0-9A-Fa-f]{2}){5})";

    GRegex *regex;
    GError *err = NULL;
    gchar *replaced_str;
 
    regex = g_regex_new(pattern, 0, 0, NULL);
    
    //MACアドレス形式の文字列を見つけ、"xxx"に置換した結果を返す
    //第三引数は第二引数の文字列の長さ(NULL終端されていれば-1でよい)
    replaced_str = g_regex_replace(regex, str, -1, 0, "xxx", 0, &err);
    g_print("Replaced: %s\n", replaced_str);

    //開放処理
    if (NULL != err) {
        g_print("match error. msg=%s\n", err->message);
        g_error_free(err);
    }
    g_free(replaced_str);
    g_regex_unref(regex);

    return 0;
}

下記のコマンドでコンパイルを行うことができます。

gcc main.c -o main `pkg-config --cflags --libs glib-2.0`

下記のコマンドで実行します。入力文字列の中から、MACアドレスの文字列がxxxに置換されました。

./main
Replaced: mac1=xxx, mac2=xxx,

名前つきグループによる文字列抽出

次に名前つきグループによる文字列抽出の使用例を示します。
文字列の中で抽出したい文字列の個数と位置が明確に決まっている場合、?P<名前>でグループに名前をつけることができ、g_match_info_fetch_namedでグループ名を指定することで、抽出した文字列を取得することができます。

下記に示すのは、X-20.5_Y2.134.logというファイル名からXとYに続く数値のみを抽出するサンプルソースです。

main.c
#include <glib.h>

int main()
{
    gchar *str = "X-20.5_Y2.134.log";
    //ログファイルからXの後ろに続く数値とYの後ろに続く数値を
    //サブセットとして取り出すパターンを作成
    gchar *pattern = "X(?P<x>[+|-]?\\d+\\.?\\d*)_Y(?P<y>[+|-]?\\d+\\.?\\d*).log";

    GRegex *regex;
    GMatchInfo *match_info;
    gchar *x_str = NULL;
    gchar *y_str = NULL;
 
    regex = g_regex_new(pattern, 0, 0, NULL);
    
    if (TRUE == g_regex_match(regex, str, 0, &match_info)) {
        g_print("str is matched.\n");
        x_str = g_match_info_fetch_named(match_info, "x");
        y_str = g_match_info_fetch_named(match_info, "y");

        g_print("x=%s, y=%s\n", (NULL != x_str) ? x_str : "Not Found."
                              , (NULL != y_str) ? y_str : "Not Found.");

        g_free(x_str);
        g_free(y_str);
    } else {
        g_print("str is not matched.\n");
    }

    //開放処理
    //g_regex_matchの結果がFALSEの場合も、match_infoはNULLではなくなるらしく、開放処理が必要
    g_match_info_free(match_info);
    g_regex_unref(regex);

    return 0;
}

下記のコマンドでコンパイルを行うことができます。

gcc main.c -o main `pkg-config --cflags --libs glib-2.0`

下記のコマンドで実行します。入力文字列の中から、狙った数値のみを抽出することができました。

./main
str is matched.
x=-20.5, y=2.134

あとがき

C言語は文字列処理のコーディングに向いておらず、入出力の基本的な処理を作るのは骨が折れます。glib2.0を活用することで、本質ではない部分に割く時間を削減し、本当に重要なことに注力できると思います。

参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?