Home

C++ で正規表現

2013-04-13 01:31:27

C++ で正規表現ってどうやるんだっけ? ということで調べていたところ、Visual C++ では STL の regex が使えると ( Visual C++ 2008 以降みたいです )。とりあえず、こんな感じで。


  #include "stdafx.h"
  #include <regex>
  #include <iostream>

  using namespace std;

  typedef std::regex_iterator<const TCHAR *> itr; 

  int _tmain(int argc, _TCHAR* argv[])
  {
    const TCHAR *pat = _T("abc123def456ghi789"); 

    itr::regex_type rx(_T("(\\d+)")); 
    itr next(pat, pat + _tcslen(pat), rx); 
    itr end; 
 
    for (; next != end; ++next) {
      _tprintf(_T("[%s] (pos: %d / len: %d)\n"),
               next->str().c_str(),
               next->position(),
               next->length());
    }
  
    return 0;
  }

普段、あんまり意識して C++ のコードを書くことはないので、STL とか苦手です。たいていの場合、C の範囲で済ませちゃいますし。いい感じにフォーマットする方法がわからなかったので、今さらながらの printf() と。ベタな方法ではありますが、やっぱり便利ですよね。

Go to TopGo to Top


JNI 呼び出し

2013-04-03 21:41:22

JNI によって、他の開発言語から jvm.dll ( C/C++ インターフェイス ) 経由で Java VM を起動することができます。ヘッダが用意されているものの、ポインタの嵐だったりするので、.NET Framework からは C/C++ のラッパー経由で呼ぶ、というのが一般的な模様。

とはいえ、P/Invoke 経由で呼べないこともないだろうと、ちょっと試してみました。その結果、なんとか呼び出すことには成功したものの、確かにえらい面倒。とりあえず、こんな感じです。まずは、構造体やら関数やらの宣言から。


  [StructLayout(LayoutKind.Sequential)]
  public struct JavaVMInitArgs
  {
    public int version;
    public int nOptions;
    public IntPtr options;
    public bool ignoreUnrecognized;
  }

  [StructLayout(LayoutKind.Sequential)]
  public struct JavaVM
  {
    public IntPtr functions; /* JNIInvokeInterface */

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate JNIResult DestroyJavaVM(
      IntPtr vm);
  }

  [StructLayout(LayoutKind.Sequential)]
  public struct JNIInvokeInterface
  {
    public IntPtr reserved0;
    public IntPtr reserved1;
    public IntPtr reserved2;

    public IntPtr DestroyJavaVM;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    public IntPtr[] __unused1;
  }

  [StructLayout(LayoutKind.Sequential)]
  public struct JNIEnv
  {
    public IntPtr functions; /* JNINativeInterface */

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate int GetVersion(
      IntPtr env);

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate IntPtr FindClass(
      IntPtr env,
      [MarshalAs(UnmanagedType.LPStr)] string name);

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate IntPtr GetStaticMethodID(
      IntPtr env,
      IntPtr clazz,
      [MarshalAs(UnmanagedType.LPStr)] string name,
      [MarshalAs(UnmanagedType.LPStr)] string sig);

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate int CallStaticIntMethodA(
      IntPtr env,
      IntPtr clazz,
      IntPtr methodID,
      jvalue[] args);
  }

  [StructLayout(LayoutKind.Sequential)]
  public struct JNINativeInterface
  {
    public IntPtr reserved0;
    public IntPtr reserved1;
    public IntPtr reserved2;
    public IntPtr reserved3;

    public IntPtr GetVersion;
    public IntPtr __unused0;
    public IntPtr FindClass;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 106)]
    public IntPtr[] __unused1;
    public IntPtr GetStaticMethodID;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
    public IntPtr[] __unused2;
    public IntPtr CallStaticIntMethodA;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
    public IntPtr[] __unused3;
  }

  [StructLayout(LayoutKind.Explicit)]
  public struct jvalue
  {
    [FieldOffset(0)] public bool   z;
    [FieldOffset(0)] public byte   b;
    [FieldOffset(0)] public char   c;
    [FieldOffset(0)] public short  s;
    [FieldOffset(0)] public int    i;
    [FieldOffset(0)] public long   j;
    [FieldOffset(0)] public float  f;
    [FieldOffset(0)] public double d;
    [FieldOffset(0)] public IntPtr l;
  }

  public enum JNIResult
  {
    JNI_OK        =   0,     /* success                     */
    JNI_ERR       = (-1),    /* unknown error               */
    JNI_EDETACHED = (-2),    /* thread detached from the VM */
    JNI_EVERSION  = (-3),    /* JNI version error           */
    JNI_ENOMEM    = (-4),    /* not enough memory           */
    JNI_EEXIST    = (-5),    /* VM already created          */
    JNI_EINVAL    = (-6),    /* invalid arguments           */
  }

  public const int JNI_VERSION_1_6 = 0x00010006;

  [DllImport("jvm.dll", CallingConvention = CallingConvention.StdCall)]
  public static extern JNIResult JNI_CreateJavaVM(
    out IntPtr pvm,
    out IntPtr penv,
    ref JavaVMInitArgs args);

最低限の宣言しかありませんし、構造体のメンバも省略してます。必要に応じて、関数やら構造体やらの宣言を追加してください。jvm.dll が公開している関数は、一部のものを除いて関数ポインタとして供給されます。ということで、.NET Framework 側では delegate として扱う必要があります。


  static private JavaVM.DestroyJavaVM destroyJavaVM;
  static private JNIEnv.GetVersion getVersion;
  static private JNIEnv.FindClass findClass;
  static private JNIEnv.GetStaticMethodID getStaticMethodID;
  static private JNIEnv.CallStaticIntMethodA callStaticIntMethodA;

呼び出し部分は、JNI_CreateJavaVM() 関数を使って JavaVM / JNIEnv を取得し、関数ポインタテーブルから必要な部分を delegate に変換する、という感じです。ポインタから構造体への変換のあたりは、.NET Framework におけるポインタ操作の基本ですね。


  IntPtr pVm;
  IntPtr pEnv;
  JavaVMInitArgs initArgs;
  JNIResult result;
  JavaVM vm;
  JNIEnv env;
  JNIInvokeInterface jiif;
  JNINativeInterface jnif;
  int version;
  IntPtr pClass;
  IntPtr pMethodID;
  jvalue[] arg = { new jvalue() };
  int exitCode;

  initArgs = new JavaVMInitArgs();
  initArgs.version = JNI_VERSION_1_6;

  result = JNI_CreateJavaVM(out pVm, out pEnv, ref initArgs);
  if (result == JNIResult.JNI_OK) {
    Console.WriteLine("JNI_CreateJavaVM OK.");
  } else {
    Console.WriteLine("JNI_CreateJavaVM NG : {0}.", result);
    goto fin;
  }

  vm =
    (JavaVM)
      Marshal.PtrToStructure(pVm, typeof(JavaVM));
  env =
    (JNIEnv)
      Marshal.PtrToStructure(pEnv, typeof(JNIEnv));
  jiif =
    (JNIInvokeInterface)
      Marshal.PtrToStructure(
        vm.functions, typeof(JNIInvokeInterface));
  jnif =
    (JNINativeInterface)
      Marshal.PtrToStructure(
        env.functions, typeof(JNINativeInterface));

  getVersion =
    (JNIEnv.GetVersion)
      Marshal.GetDelegateForFunctionPointer(
        jnif.GetVersion, typeof(JNIEnv.GetVersion));
  version = getVersion.Invoke(pEnv);
  Console.WriteLine("JVM version : 0x{0:x}", version);

  findClass =
    (JNIEnv.FindClass)
      Marshal.GetDelegateForFunctionPointer(
        jnif.FindClass, typeof(JNIEnv.FindClass));
  pClass = findClass.Invoke(pEnv, "SampleJavaClass");

  getStaticMethodID =
    (JNIEnv.GetStaticMethodID)
      Marshal.GetDelegateForFunctionPointer(
        jnif.GetStaticMethodID,
        typeof(JNIEnv.GetStaticMethodID));
  pMethodID =
    getStaticMethodID.Invoke(
      pEnv, pClass, "main", "([Ljava/lang/String;)V");
  Console.WriteLine("---------------------");

  callStaticIntMethodA =
    (JNIEnv.CallStaticIntMethodA)
      Marshal.GetDelegateForFunctionPointer(
        jnif.CallStaticIntMethodA,
        typeof(JNIEnv.CallStaticIntMethodA));
  exitCode =
    callStaticIntMethodA.Invoke(pEnv, pClass, pMethodID, arg);
  Console.WriteLine("exit code : {0}", exitCode);

  destroyJavaVM =
    (JavaVM.DestroyJavaVM)
      Marshal.GetDelegateForFunctionPointer(
        jiif.DestroyJavaVM,
        typeof(JavaVM.DestroyJavaVM));
  destroyJavaVM.Invoke(pVm);

fin:
  Console.WriteLine("------ finish. ------");
  Console.ReadLine();
}

といったところで、パスの通ったところに jvm.dll があること、CLASSPATH が通ったところ ( という表現が正しいのか、Java 初心者のわたしはよくわかりません ) に呼び出し対象の .jar を置いて実行できました。

と思ったら、こんなプロジェクト ( csjni ) を見つけてしまいました。ちぇー。



Go to TopGo to Top