XREAでWordPressの表示速度を改善する方法 まとめ

2月 13th, 2010

週末をつかって、このブログ(WordPress)の表示速度改善に取り組んでみました。
ひどいときは10秒も表示にかかってました。

遅かった主原因はAmazonのコンテンツ連動広告なのですが、それ以外でもいろいろ調整したので
メモを残しておきます。WP-CacheなどのWordPressのプラグインについては、そこらじゅうで言及されてるので省略。

最終的に5秒が1秒になったよ!

ページ速度改善

ページ速度改善

gzip圧縮

CSSやJavaScriptなどをgzipで圧縮して、通信料を減らします。WPのディレクトリに以下の内容を.htaccessという名前で保存します。
mod_gzip_temp_dir に指定するディレクトリをあらかじめパーミッション777で作成しておく必要があります。

<IfModule mod_gzip.c>
  mod_gzip_on Yes
  mod_gzip_keep_workfiles Yes
  mod_gzip_minimum_file_size  1024
  mod_gzip_maximum_file_size  0
  mod_gzip_maximum_inmem_size 60000
  mod_gzip_dechunk Yes
  mod_gzip_temp_dir "/virtual/majide/public_html/blog.majide.com/tmp"
  mod_gzip_item_include  mime "application/x-httpd-cgi"
  mod_gzip_item_include  mime "application/x-httpd-php"
  mod_gzip_item_include  mime "application/x-javascript"
  mod_gzip_item_include  mime text/*
  mod_gzip_item_include  mime "httpd/unix-directory"
  mod_gzip_item_include  file "\.shtml$"
  mod_gzip_item_include  file "\.htm$"
  mod_gzip_item_include  file "\.html$"
  mod_gzip_item_include  file "\.php$"
  mod_gzip_item_include  file "\.pl$"
  mod_gzip_item_include  file "\.cgi$"
  mod_gzip_item_include  file "\.css$"
  mod_gzip_item_include  file "\.js$"
  mod_gzip_item_exclude  mime "image/.*"
  mod_gzip_min_http 1001
</IfModule>

Expires ヘッダの追加

HTTPレスポンスヘッダにExpiresヘッダを加えると、コンテンツの有効期限を設定することができます。
ブラウザは設定された有効期限内であれば、ローカルにキャッシュされたファイルを利用します。

※注意 一度、キャッシュされたデータは有効期限がくるまで更新されません。
画像を更新する場合などはファイル名も変更し、キャッシュされたデータが使われないようにする必要があります。

XREAにはmod_expiresモジュールがインストールされていないため、mod_headersモジュールを利用してムリヤリExpiresヘッダを設定します。mod_headersは任意のHTTPレスポンスヘッダを設定するモジュールです。

■ mod_headers の使用例

Header set Expires Sat, 20 Feb 2010 08:21:05 GMT

mod_headersでは固定の文字列しか設定することができないので、Expiresヘッダを動的に生成するcronを仕込みます。
以下の例では、画像(jpg,png,gif)の有効期限を1週間に設定しています。

<?php
// 上書きする.htaccessファイルのパス
define('HTACCESS_PATH', '/virtual/majide/public_html/blog.majide.com/.htaccess');
define('TMP_HTACCESS_PATH', '/virtual/majide/public_html/blog.majide.com/.htaccess_tmp');

$offset = 7 * 24 * 60 * 60; //有効期限は7日
$expire = gmdate('D, d M Y H:i:s', time() + $offset)." GMT";

// ここにもともとの.htaccessの内容を記載
$htaccess = '

<IfModule mod_gzip.c>
  mod_gzip_on Yes
  mod_gzip_keep_workfiles Yes
  mod_gzip_minimum_file_size  1024
  mod_gzip_maximum_file_size  0
  mod_gzip_maximum_inmem_size 60000
  mod_gzip_dechunk Yes
  mod_gzip_temp_dir "/virtual/majide/public_html/blog.majide.com/tmp"
  mod_gzip_item_include  mime "application/x-httpd-cgi"
  mod_gzip_item_include  mime "application/x-httpd-php"
  mod_gzip_item_include  mime "application/x-javascript"
  mod_gzip_item_include  mime text/*
  mod_gzip_item_include  mime "httpd/unix-directory"
  mod_gzip_item_include  file "\.shtml$"
  mod_gzip_item_include  file "\.htm$"
  mod_gzip_item_include  file "\.html$"
  mod_gzip_item_include  file "\.php$"
  mod_gzip_item_include  file "\.pl$"
  mod_gzip_item_include  file "\.cgi$"
  mod_gzip_item_include  file "\.css$"
  mod_gzip_item_include  file "\.js$"
  mod_gzip_item_exclude  mime "image/.*"
  mod_gzip_min_http 1001
</IfModule>

';

$htaccess .= <<<END
<FilesMatch "\.(png|jpe?g\|gif)$">
  <IfModule mod_headers.c>
    Header set Expires $expire
  </IfModule>
</FilesMatch>

END;

if (file_put_contents(TMP_HTACCESS_PATH, $htaccess)) {
    rename(TMP_HTACCESS_PATH, HTACCESS_PATH);
}

?>

Xreaでは、cronは必ずシェルでなければならない制限があるので、PHPを実行するシェルを用意します。

#!/bin/sh

/usr/local/bin/php /virtual/majide/genhtaccess.php

最後にXREAの管理画面からシェルスクリプトをcronに設定して完了です。動かすのは1日に1回程度で十分でしょう。

XREAのcron設定画面

XREAのcron設定画面

参考文献

ハイパフォーマンスWebサイト ―高速サイトを実現する14のルール
ハイパフォーマンスWebサイト
スケーラブルWebサイト
スケーラブルWebサイト
Apacheクックブック 第2版 ―Webサーバ管理者のためのレシピ集
Apacheクックブック

参考URL

Macbook WhiteにLinux CentOS 5.3をインストール No.2

5月 28th, 2009

NdiswrapperとUnRARのインストール

まず、NdiswrapperとUnRARをインストールします。NdiswrapperとUnRARに必要なその他のRPMはCentOSのインストールディスクに入っているはずです。NdiswrapperはWindowsのドライバをLinux上で動作させるためのソフトウェアです。

$ rpm -ivh unrar-3.7.4-1.el5.rf.i386.rpm dkms-ndiswrapper-1.48-1.el5.rf.i386.rpm dkms-2.0.17.6-1.el5.rf.noarch.rpm

無線LANドライバのインストール

BootCampのCDからWindows用のドライバをコピーしてきますます。
exeファイルをunrarで解凍し、ファイルを取り出します。

$ mkdir ~/broadcomdriver
$ cp “/media/WindowsSupport/boot camp/drivers/broadcom/broadcomxpinstaller.exe” ~/broadcomdriver
$ cd ~/broadcomdriver
$ unrar x broadcomxpinstaller.exe

infファイルをndiswrapperに読み込ませてドライバをインストールします。

$ sudo /usr/sbin/ndiswrapper -i bcmwl5.inf

$ sudo /usr/sbin/ndiswrapper -l
bcmwl5 : driver installed
device (14E4:432B) present

$ sudo /usr/sbin/ndiswrapper -m
adding “alias wlan0 ndiswrapper” to /etc/modprobe.d/ndiswrapper …

これでドライバのインストールは完了です。引き続きネットワークインターフェイスを設定します。
/etc/sysconfig/network-scripts/ifcfg-wlan0に以下の内容を設定します。

# Please read /usr/share/doc/initscripts-*/sysconfig.txt
# for the documentation of these parameters.
TYPE=Wireless
DEVICE=wlan0
HWADDR=
BOOTPROTO=dhcp
NETMASK=
DHCP_HOSTNAME=
IPADDR=
DOMAIN=
ONBOOT=yes
USERCTL=no
IPV6INIT=no
PEERDNS=yes
ESSID=
CHANNEL=Auto
MODE=Auto
WPA=yes
SECURITYMODE=open
RATE=auto

WEPを利用している場合は、暗号キーを以下のファイルに記載します。
/etc/sysconfig/network-scripts/keys-wlan0

KEY=xxxxxxxxxxxxxxxxxxxxxxxxx

WPAを利用している場合はもう少し込み入った設定が必要です。詳しくは、wpa_supplicantのマニュアルに記載されています。

設定が終わったら、最後にifupでインターフェイスを有効化します。

$ sudo /sbin/ifup wlan0

残る問題

  • 有線LANが使えない
  • 音がならない
  • デュアルモニタにできない
  • 右クリックができない
  • キーボードのアンダーバー、パイプが効かない

Macbook WhiteにLinux CentOS 5.3をインストール No.1

5月 25th, 2009

Macbook White のスペック

Intel Core 2 Duo P7350 @ 2GHz
NVIDIA GeForce 9400M
Memory 2GB
Broadcom corporation BCM4332 802.11a/b/g/n Wireless LAN Controller

下準備

  1. Mac OS X インストール ディスク。
    BootCampからWindowsのドライバを取り出す必要があるので、OS Xのインストールディスクも必要です。
  2. Cent OS インストール ディスク
    Cent OSのサイトからISOイメージをダウンロードして、DVDに焼いておきます。
    今回は64bit版ではなく、i386を選択しました。
  3. その他、ドライバ類。
    インストール直後の状態では、ドライバがインストールされていないため、ネットワークにつなぐことができません。最低限ネットワークにつなぐために必要なドライバなどをCD-Rなどに焼いておきます。

パーティションの作成

ディスクユーティリティでLinux用のパーティションを作成します。のちほどCentOSインストール時にフォーマットしなおすので、フォーマットは何でもかまいません。
partision

rEFIt ブートマネージャのインストール

rEFItをインストールすると、起動時にOSを選択できるようになります。
http://refit.sourceforge.net/

CentOSのインストール

CentOSのインストールディスクを入れて、「C」を押しながら再起動すると、ディスクからBootします。
ACPIが有効だとうまくインストーラーが立ち上がらないので、bootプロンプトでカーネルオプションを指定します。

boot : linux noapic acpi=off apm=on
install centOS5

install centOS5

swap用のパーティションがないと怒られますが無視します。

キーボードの設定

初期状態では、アンダーバー、バックスラッシュ、パイプなどのキーが効きません。
xmodmapを設定してキーを割り当てます。
以下の例はF12にパイプ、F11にバックスラッシュ、F9にアンダーバーを割り当てています。
他のキーに割り当てたい場合はxevコマンドでkeycodeを確認できます。

~/.xmodmap
keycode 75 = underscore
keycode 95 = backslash
keycode 96 = bar

# xmodmapの設定読み込み
$ xmodmap ~/.xmodmap

続きます。

参考文献

VistaもXPもMac上で動かせる!Windows on Mac パーフェクトガイド2009
VistaもXPもMac上で動かせる!Windows on Mac パーフェクトガイド2009
Mac・Windows・Linuxが1台で使える
Mac・Windows・Linuxが1台で使える

Windows 再インストール時の手順

4月 6th, 2009

データの移行漏れなどがないよう、自分が作業するときの手順をメモっておきます。

前準備

  1. 単語辞書を書き出す
  2. Firefoxのデータのバックアップ → Firefoxの設定情報をバックアップする
  3. iTunesのデータのバックアップと認証の解除

OSインストールとドライバインストール

以下の順番でインストールをすると不具合が少ない。

  1. OSインストール
  2. WindowsUpdate
  3. チップセットドライバ(INFパッチ)を入れる
  4. DirectX入れる
  5. WindowsUpdate(DirectX)
  6. グラフィックボードのドライバ入れる
  7. その他ドライバ入れる

アプリケーションのインストールと各種設定

  1. IEのテンポラリ領域をCドライブ以外に設定
  2. Cドライブにスワップしないよう設定
  3. データのバックアップのタスク設定
  4. ウィルス対策のソフトを忘れずに入れる
  5. その他いつものアプリ入れる
  6. WindowsUpdate
  7. デブラグ

FirefoxのAddon

いつものAddon

  1. All-in-One Gestures
  2. Screen grab
  3. tab Mix Plus
  4. IE Tab

ADT(Android Development Tools) のインストール

4月 2nd, 2009

Android Development Tools for Eclipse とは

ADTを導入することで、EclipseでAndroidのプロジェクトが作成可能になります。Andoroidの開発には必須のツールです。

Eclipse のダウンロード・インストール

まずは、Eclipse がないと始まりません。

  1. EclipseをEclipseのサイトのDownloadsからダウンロードします。
    Eclipse ダウンロード

    Eclipse ダウンロード

  2. Eclipse IDE for Java Developers を選択
  3. ダウンロードしたファイルを解凍し、「C:\Program Files\」等に置く

ADTのダウンロードとインストール

  1. ADTはAndoroidのDeveloperサイトからダウンロードできます。
  2. ダウンロードしたADT-X.X.X.zip ファイルは解凍する必要はありません。
  3. Eclipseを起動し、Eclipseの「Help」メニューから「Software Updates」を選択します。
    HelpメニューからSoftwareUpdatesを選択

    HelpメニューからSoftwareUpdatesを選択

  4. 「Add Sites」を選択し、「Archive」から先ほどダウンロードしたADTのzipファイルを指定します。
    Add SitesからArchiveを選択

    Add SitesからArchiveを選択

  5. zipファイルの中身が表示されるので、「Developer Tools」を選択し、「Install」を実行します。
    Developer Toolsを選択

    Developer Toolsを選択

  6. ライセンスの確認画面が出るので、Acceptを選択し、インストールを進めます。
    ADTのライセンスの確認

    ADTのライセンスの確認

  7. インストールが終わったら、Eclipseを再起動して完了です。

Android SDKの設定

  1. 「Window」メニューから「Preference」を選択します
    adk-preference
  2. 「Android」を選択し、「SDK Location」にAndroid SDKの場所を設定します。
    android_dev_tool_path

設定の確認

  1. 新規プロジェクト画面でAndroid プロジェクトが作成可能になっていることを確認します。
    Eclipse Android Project

    Eclipse Android Project

参考文献

Google Androidアプリケーション開発入門 画面作成からデバイス制御まで――基本機能の全容
Google Androidアプリケーション開発入門
Google Androidプログラミング入門
Google Androidプログラミング入門

全国郵便番号XMLデータ

3月 30th, 2009

日本郵政の郵便番号データをXML形式に変換したものを用意する機会があったので、公開してみます。
文字コードはUTF-8です。

attachment filejp_zipcode (1.8MB)

フォーマットは以下のような形式になっています。

<?xml version="1.0"?>
<JapanAreaData>
  <Prefecture>
    <PrefectureKana>ホッカイドウ</PrefectureKana>
    <PrefectureName>北海道</PrefectureName>
    <City>
      <CityName>札幌市中央区</CityName>
      <CityNameKana>サッポロシチュウオウク</CityNameKana>
      <Area>
        <AreaKana>アサヒガオカ</AreaKana>
        <AreaName>旭ケ丘</AreaName>
        <ZipCode>0640941</ZipCode>
      </Area>
      <Area>
        <AreaKana>オオドオリヒガシ</AreaKana>
        <AreaName>大通東</AreaName>
        <ZipCode>0600041</ZipCode>
      </Area>
            :
    </City>
    <City>
      <CityName>札幌市北区</CityName>
      <CityNameKana>サッポロシキタク</CityNameKana>
              :
    </City>
  </Prefecture>
  <Prefecture>
    <PrefectureKana>アオモリケン</PrefectureKana>
    <PrefectureName>青森県</PrefectureName>
          :
  </Prefecture>
</JapanAreaData>

元データは日本郵政のサイトにおいてある、CSVファイルです。Perlで書いた変換スクリプトでXMLに変換しました。

郵便番号CSVデータをXMLに変換するスクリプト

#!/usr/bin/perl

use strict;
use XML::Simple;

my $hash;
my %tmp_hash;
my $i;

$hash->{'Prefecture'} = [];

my $current_pref;
my $current_city;
my $pref_prefix = -1;
my $city_prefix = -1;

while (<>) {
        chomp;
        s/"//g;
        my ($idnum, $zip5, $zip7, $pref_kana, $city_kana, $area_kana, $pref, $city, $area) = split(/,/);

        if ($area eq '以下に掲載がない場合') {
                next;
        }

        if ($current_pref ne $pref) {
                $pref_prefix++;
                $city_prefix = -1;

                $current_pref = $pref;
                $current_city = "";

                push(@{$hash->{'Prefecture'}}, { 'PrefectureName' => $pref, 'PrefectureKana' => $pref_kana, 'City' => [] });
        }

        if ($current_city ne $city) {
                $city_prefix++;
                $current_city = $city;

                push(@{$hash->{'Prefecture'}[$pref_prefix]->{'City'}}, { 'CityName' => $city, 'CityNameKana' => $city_kana, 'Area' => [] });
        }
        push(@{$hash->{'Prefecture'}[$pref_prefix]->{'City'}[$city_prefix]->{'Area'}}, { 'ZipCode' => $zip7, 'AreaName' => $area, 'AreaKana' => $area_kana });
}

print XMLout($hash,  NoAttr => 1, RootName => 'JapanAreaData');

プロファイラ gprof の使い方

3月 26th, 2009

gprof GNU Profiler とは

プロファイラあるプログラム中で使用される関数毎に、その実行回数や実行時間を分析して表示するツールです。プログラムが思ったようなパフォーマンスが出ない場合、ボトルネックになっている場所を特定するために利用します。

実行例

  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
  0.0       0.00     0.00        3     0.00     0.00  read [1] //read()が3回
  0.0       0.00     0.00        2     0.00     0.00  write [2] //write()が2回 呼ばれている
  0.0       0.00     0.00        1     0.00     0.00  ___sysctl [138]
  0.0       0.00     0.00        1     0.00     0.00  _close [139]
  0.0       0.00     0.00        1     0.00     0.00  _mcleanup (140)
  0.0       0.00     0.00        1     0.00     0.00  _profil [141]
  0.0       0.00     0.00        1     0.00     0.00  moncontrol [3]
  0.0       0.00     0.00        1     0.00     0.00  open [4]
  0.0       0.00     0.00        1     0.00     0.00  sysctl [5]

それぞれ、

  • 実行時間(全体に対する %)
  • 実行時間の累積(秒)
  • 実行時間(秒)
  • 関数の実行された回数
  • 1回の関数実行にかかる時間(ミリ秒)
  • 1回の関数実行にかかる時間の合計(ミリ秒)
  • 関数名

を表しています。

使い方

gprofを使うには「-pg」オプションをつけてコンパイルする必要があります。

$ gcc -pg -o test.o test.c

あとは、実行ファイルを普通に実行します。このとき、gprofのデータファイルが同じディレクトリに生成されます。

$ ./test.o

「gprof 実行ファイル データファイル」とすると、解析結果が出力されます。

$ gprof test.o test.o.gmon

参考文献

Debug Hacks -デバッグを極めるテクニック&ツール
Debug Hacks
GNU Make 第3版
GNU Make 第3版

参考URL

Makefile中の環境変数を無視する

3月 26th, 2009

Makefile中の環境変数を無視する

「-e」オプションでMakefile中で設定されている環境変数を上書きすることができる。

サンプルMakefile

CFLAGS = -O -Wall

a.out: main.c
$(CC) $(CFLAGS) main.c -o $@

make

$ make //普通にmake
cc -O -Wall main.c -o a.out

$ export CFLAGS=” //CFLAGSをなしに
$ touch main.c
$ make -e
cc main.c -o a.out

「-e」オプションの説明
Makeファイル中の変数を上書きする。

-e Specify that environment values override macro assignments within
makefiles for all variables.

参考文献

GNU Make 第3版
GNU Make
CとGNU開発ツールによる組み込みシステムプログラミング 第2版
CとGNU開発ツールによる組み込みシステムプログラミング
GNUソフトウェアプログラミング ―オープンソース開発の原点
GNUソフトウェアプログラミング

[C言語]共有メモリ(shm)を読み書きするサンプルコード

3月 19th, 2009

共有メモリとは

共有メモリはその名の通り、複数のプロセスで共有できるメモリである。
プロセス間通信(IPC)に利用される。
親プロセス、子プロセス、無関係なプロセス、どの関係であってもデータの共有が可能。

共有メモリの操作には下記のシステムコールを利用する。

システムコール 説明
shmget() 共有メモリ・セグメント識別子を獲得する
shmat() 自プロセスのデータセグメントにマップ(アタッチとも呼ぶ)する
shmdt() 共有メモリをアンマップ(デタッチとも呼ぶ)する
shmctl() 共有メモリをシステム上から削除する

サンプルプログラム

shm_receiver.c

shmを生成し、1秒置きに、shmの中身を画面に表示する。shmの中身が「end」になると、終了する。

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strcpy */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(void)
{
    int  id;
    char *adr;

    /* IPC_PRIVATEを指定すると、新規にshmが生成される。*/
    if((id = shmget(IPC_PRIVATE, 512, IPC_CREAT|0666)) == -1){
        perror("shmget");
        exit(-1);
    }

    printf("共有メモリID = %d\n",id);

    /* char形で取得 */
    if(( adr = (char *)shmat(id, NULL, 0)) == (void *)-1){
        perror("shmat");
    } else {
        strcpy(adr,"Initial");
        /* 1秒ごとに出力 */
        while(1){
            printf("%s\n",adr);
            /* 「end」で終了 */
            if (strcmp(adr, "end") == 0) {
                break;
            }
            sleep(1);
        }

        if(shmdt(adr)==-1){
            perror("shmdt");
        }
    }

    /* shmの破壊をする */
    if(shmctl(id, IPC_RMID, 0)==-1){
        perror("shmctl");
        exit(EXIT_FAILURE);
    }

    return 0;
}

shm_writer.c

コマンドラインから与えられた文字列をshmにコピーする。

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* strcpy */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main(int argc, char *argv[])
{
    int   id;
    char  *adr;

    if( argc <= 2) {
        fprintf(stderr, "Usage: shm_writer shm_id string\n");
        exit(EXIT_FAILURE);
    }

    id = atoi(argv[1]);

    if(( adr = (char *)shmat(id,0,0)) == (void *)-1) {
        perror("shmat");
    } else {
        strcpy(adr, argv[2]);
        fprintf(stderr, "written.\n");
        if( shmdt(adr) == -1) {
            perror("shmdt");
        }
    }
}

実行例

$ gcc shm_receiver.c -o shm_receiver
$ gcc shm_writer.c -o shm_writer

$ shm_receiver
共有メモリID = 1234 ←IDを覚えておく
Initial

$ shm_writer 1234 hogehoge //shmに「hogehoge」を書き込む。
$ shm_writer 1234 end //shm_receverが終了する。

参考文献

詳解UNIXプログラミング
詳解UNIXプログラミング
例解UNIXプログラミング教室
例解UNIXプログラミング教室
C言語によるUNIXシステムプログラミング入門
C言語によるUNIXシステムプログラミング入門

参考URL

構築環境

FreeBSD 4.10-RELEASE

[C言語]正規表現 サンプルコード

3月 16th, 2009

regex.h

C言語で正規表現を使うにはregex.hをincludeします。
具体的に利用する関数はregcomp(), regexec(), regfree()関数の3つです。

regcomp() 関数

int regcomp(regex_t *preg, const char *regex, int cflags)
正規表現のコンパイルを行なう。コンパイル成功時には0を返す。cflags には以下に示す定数一つ以上のビットごとの OR (bitwise-or) を指定する。

REG_EXTENDED
regex に POSIX 拡張正規表現を使用する。もしこのフラグが設定されない場合、POSIX 標準正規表現が使われる。
REG_ICASE
大文字小文字の違いを無視する。
REG_NOSUB
このフラグを設定してコンパイルされたパターンバッファが regexec の引数に指定されると、パラメータ nmatch, pmatch が無視される。
REG_NEWLINE
全ての文字にマッチするオペレータに改行をマッチさせない。

regexec() 関数

int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
正規表現による検索を実行する。eflags には以下に示す定数一つ以上のビットごとの OR (bitwise-or) を指定する。

REG_NOTBOL
行頭にマッチするオペレータは、必ずマッチに失敗する (コンパイル時のフラグ REG_NEWLINE の項目も参照)。このフラグは、複数行にまたがる文字列を regexec() で検索する際に、文字列の先頭を行の先頭として解釈させない場合に用いる。
REG_NOTEOL
行末にマッチするオペレータは、必ずマッチに失敗する。

regfree()関数

void regfree(regex_t *preg)
正規表現パターンバッファを解放する。

正規表現サンプルコード

カンマ区切りの文字列から、数値を取り出す。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
 
int main() {
     char str[] = "123, 456, 789";
     regex_t preg;
     size_t nmatch = 5;
     regmatch_t pmatch[nmatch];
     int i, j;
 
     if (regcomp(&preg, "([[:digit:]]+), ([[:digit:]]+), ([[:digit:]]+)", REG_EXTENDED|REG_NEWLINE) != 0) {
         printf("regex compile failed.\n");
         exit(1);
     }
 
     printf("String = %s\n", str);
 
     if (regexec(&preg, str, nmatch, pmatch, 0) != 0) {
         printf("No match.\n");
     } else {
         for (i = 0; i < nmatch; i++) { /* nmatch にマッチした件数が入る */
             printf("Match position = %d, %d , str = ", (int)pmatch[i].rm_so, (int)pmatch[i].rm_eo);
             if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0) {
                 for (j = pmatch[i].rm_so ; j < pmatch[i].rm_eo; j++) {
                     putchar(str[j]);
                 }
             }
             printf("\n");
         }
     }
 
     regfree(&preg);
     return 0;
}

実行結果

$ gcc regex-sample.c
$ ./a.out
String = 123, 456, 789
Match position = 0, 13 , str = 123, 456, 789
Match position = 0, 3 , str = 123
Match position = 5, 8 , str = 456
Match position = 10, 13 , str = 789
Match position = -1, -1 , str =

参考文献

反復学習ソフト付き 正規表現書き方ドリル (WEB+DB PRESS plus)
反復学習ソフト付き
正規表現書き方ドリル

詳説 正規表現 第3版
詳説 正規表現
プログラミング言語C 第2版 ANSI規格準拠
プログラミング言語C

参考URL