首先分享一些我在网上找到的参考资料:
-
根据mxChar描述,
MATLAB 在计算机上将字符存储为 2 字节 Unicode 字符
多字节字符集
MBCS 这个术语还是有点模糊的对我来说,我认为他们在这种情况下意味着 UTF-16 (尽管我不确定代理对,这可能会使其成为 UCS-2)。
UPDATE:MathWorks 将措辞更改为:
MATLAB 对 Unicode 字符使用 16 位无符号整数字符编码。
The mxArrayToString页面声明它确实处理多字节编码字符(取消链接mxGetString它仅处理单字节编码方案)。不幸的是,没有关于如何执行此操作的示例。
最后,这里有一个thread在 MATLAB 新闻组上,其中提到了几个与此相关的未记录函数(您可以通过加载libmx.dll
库变成像这样的工具依赖步行者在 Windows 上)。
这是我在 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!
}
我用 C 代码创建了三个字符串,分别使用 ASCII、UTF-8 和 UTF-16LE 编码。然后我使用以下命令将它们传递给 MATLABmxCreateString
MEX 函数(及其其他未记录的版本)。
我通过咨询得到了字节序列文件格式.info网站:一个 (U+0041), À (U+00C0), and 水 (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_string AÀ水](https://i.stack.imgur.com/gCtAj.png)
我正在利用嵌入式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))
最后我应该说,如果由于某种原因你仍然遇到问题,
最简单的事情是将非 ASCII 字符串转换为uint8
数据类型
在将其从 MATLAB 传递到您的引擎程序之前。
所以在 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);
并使用 Engine 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
希望这可以帮助..
EDIT:
在 MATLAB R2014a 中,许多无证的C 函数已从libmx
库(包括上面使用的库),并替换为命名空间下公开的等效 C++ 函数matrix::detail::noninlined::mx_array_api
.
调整上面的示例应该很容易(如所解释的here)在最新的 R2014a 版本上运行。