3

MATLAB エンジンまたは MEX C インターフェイスを介して、MATLAB 文字列の基礎となる Unicode データにアクセスするにはどうすればよいですか?

これが例です。Unicode 文字を UTF-8 でエンコードされたファイル test.txt に入れ、次のように読み取ります。

fid=fopen('test.txt','r','l','UTF-8');
s=fscanf(fid, '%s')

MATLAB で。

最初に を実行しfeature('DefaultCharacterSet', 'UTF-8')、次に C から実行するとengEvalString(ep, "s")、出力としてファイルからテキストが UTF-8 として返されます。これは、MATLAB が内部的に Unicode として保存することを証明しています。ただし、そうすると、MATLAB で得mxArrayToString(engGetVariable(ep, "s"))られるものunicode2native(s, 'Latin-1')が得られます。Latin-1 以外のすべての文字が文字コード 26 に置き換えられます。必要なのは、基礎となる Unicode データに任意の Unicode 形式 (UTF-8) の C 文字列としてアクセスすることです。 、UTF-16 など)、および非 Latin-1 文字を保持します。これは可能ですか?

私のプラットフォームは OS X、MATLAB R2012b です。

補遺:ドキュメントには、「[mxArrayToString()] はマルチバイトでエンコードされた文字をサポートする」と明示的に記載されていますが、それでも元のデータの Latin-1 近似しか得られません。

4

1 に答える 1

7

まず、オンラインで見つけたいくつかの参考資料を共有しましょう。

  • mxChar説明によると、

    MATLABは、マルチバイト文字セットを備えたマシンに文字を2バイトUnicode文字として格納します

    それでも、MBCSという用語は私には多少あいまいですが、このコンテキストではUTF-16を意味していると思います(ただし、代理ペアについてはわかりませんが、おそらく代わりにUCS-2になります)。

    更新: MathWorksは文言を次のように変更しました:

    MATLABは、Unicode文字に16ビットの符号なし整数文字エンコードを使用します。

  • このmxArrayToStringページには、マルチバイトでエンコードされた文字(mxGetStringシングルバイトのエンコードスキームのみを処理するリンク解除)が処理されると記載されています。残念ながら、これを行う方法の例はありません。

  • 最後に、これに関連するいくつかの文書化されていない関数について言及しているMATLABニュースグループのスレッドがあります(WindowsのDependency Walkerlibmx.dllなどのツールにライブラリをロードすることでそれらを見つけることができます)。


これが私がMEXで行った小さな実験です:

my_func.c

#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    char str_ascii[] = {0x41, 0x6D, 0x72, 0x6F, 0x00};   // {'A','m','r','o',0}
    char str_utf8[] = {
        0x41,                   // U+0041
        0xC3, 0x80,             // U+00C0
        0xE6, 0xB0, 0xB4,       // U+6C34
        0x00
    };
    char str_utf16_le[] = {
        0x41, 0x00,             // U+0041
        0xC0, 0x00,             // U+00C0
        0x34, 0x6C,             // U+6C34
        0x00, 0x00
    };

    plhs[0] = mxCreateString(str_ascii);
    plhs[1] = mxCreateString_UTF8(str_utf8);        // undocumented!
    plhs[2] = mxCreateString_UTF16(str_utf16_le);   // undocumented!
}

ASCII、UTF-8、UTF-16LEでそれぞれエンコードされたCコードで3つの文字列を作成します。mxCreateString次に、 MEX関数(およびその他の文書化されていないバージョン)を使用して、それらをMATLABに渡します。

Fileformat.info Webサイトを参照してバイトシーケンスを取得しました: A(U + 0041)À(U + 00C0)、および水(U + 6C34)

上記の関数をMATLAB内でテストしてみましょう。

%# call the MEX function
[str_ascii, str_utf8, str_utf16_le] = my_func()

%# MATLAB exposes the two strings in a decoded form (Unicode code points)
double(str_utf8)       %# decimal form: [65, 192, 27700]
assert(isequal(str_utf8, str_utf16_le))

%# convert them to bytes (in HEX)
b1 = unicode2native(str_utf8, 'UTF-8')
b2 = unicode2native(str_utf16_le, 'UTF-16')
cellstr(dec2hex(b1))'  %# {'41','C3','80','E6','B0','B4'}
cellstr(dec2hex(b2))'  %# {'FF','FE','41','00','C0','00','34','6C'}
                       %# (note that first two bytes are BOM markers)

%# show string
view_unicode_string(str_utf8)

unicode_stringAÀ水"></p><p>私は<ahref=を利用しています文字列を表示するための埋め込みJava機能:

function view_unicode_string(str)
    %# create Swing JLabel
    jlabel = javaObjectEDT('javax.swing.JLabel', str);
    font = java.awt.Font('Arial Unicode MS', java.awt.Font.PLAIN, 72);
    jlabel.setFont(font);
    jlabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);

    %# place Java component inside a MATLAB figure
    hfig = figure('Menubar','none');
    [~,jlabelHG] = javacomponent(jlabel, [], hfig);
    set(jlabelHG, 'Units','normalized', 'Position',[0 0 1 1])
end

次に、逆方向に作業してみましょう(MATLABからCへの文字列を受け入れます)。

my_func_reverse.c

#include "mex.h"

void print_hex(const unsigned char* s, size_t len)
{
    size_t i;
    for(i=0; i<len; ++i) {
        mexPrintf("0x%02X ", s[i] & 0xFF);
    }
    mexPrintf("0x00\n");
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    char *str;
    if (nrhs<1 || !mxIsChar(prhs[0])) {
        mexErrMsgIdAndTxt("mex:error", "Expecting a string");
    }
    str = mxArrayToString_UTF8(prhs[0]); // get UTF-8 encoded string from Unicode
    print_hex(str, strlen(str));         // print bytes
    plhs[0] = mxCreateString_UTF8(str);  // create Unicode string from UTF-8
    mxFree(str);
}

そして、MATLABの内部からこれをテストします。

>> s = char(hex2dec(['0041';'00C0';'6C34'])');   %# "\u0041\u00C0\u6C34"
>> ss = my_func_reverse(s);
0x41 0xC3 0x80 0xE6 0xB0 0xB4 0x00               %# UTF-8 encoding
>> assert(isequal(s,ss))

uint8最後に、何らかの理由でまだ問題が発生している場合は、MATLABからエンジンプログラムに渡す前に、非ASCII文字列をデータ型に変換するのが最も簡単な方法です。

したがって、MATLABプロセス内で次のことを行います。

%# read contents of a UTF-8 file
fid = fopen('test.txt', 'rb', 'native', 'UTF-8');
str = fread(fid, '*char')';
fclose(fid);
str_bytes = unicode2native(str,'UTF-8');  %# convert to bytes

%# or simply read the file contents as bytes to begin with
%fid = fopen('test.txt', 'rb');
%str_bytes = fread(fid, '*uint8')';
%fclose(fid);

次のようにエンジンAPIを使用して変数にアクセスします。

mxArray *arr = engGetVariable(ep, "str_bytes");
uint8_T *bytes = (uint8_T*) mxGetData(arr);
// now you decode this utf-8 string on your end ...

すべてのテストは、デフォルトの文字セットを使用してR2012bを実行しているWinXPで実行されました。

>> feature('DefaultCharacterSet')
ans =
windows-1252

お役に立てれば..


編集:

MATLAB R2014aでは、ドキュメント化されていない多くのC関数libmx(上記で使用されているものを含む)がライブラリから削除され、名前空間で公開されている同等のC++関数に置き換えられましたmatrix::detail::noninlined::mx_array_api

上記の例(ここで説明)を調整して、最新のR2014aバージョンで実行するのは簡単です。

于 2013-02-19T16:31:07.590 に答える