Matlab中的字符串与元胞数组

1. 字符串

1.1 为什么

这两个东西拉在一起讲,是因为在2016a之前的Matlab中,要表示一个字符串的数组,只能用元胞数组。

最初的字符串在Matlab中的类型是字符,在Matlab中,一个字符就是一个长度为1的字符串,而一个字符串就是一个长度大于1的字符数组。这就造成,要表示一个字符串数组,就只能用元胞数组。因为Matrix只能是方阵……

所以当时我们要在一个图上画几条线,每条线的名字是一个字符串,就只能用元胞数组。

x = 1:10;
y = [x; x.^2; x.^3];
plot(x, y);
legends = {'y = x', 'y = x * x', 'y = x * x * x'};
legend(legends);

011_string_and_cell_in_Matlab中的字符串与元胞数组-LMLPHP

1.2 真正的字符串类型string

2016a之后,Matlab引入了字符串类型,string,这个类型的引入,使得我们可以直接用字符串数组来表示字符串数组了。

x = 1:10;
y = [x; x.^2; x.^3];
plot(x, y);
legends = ["y = x", "y = x * x", "y = x * x * x"];
legend(legends);

字符串类型的是"",字符类型是'',居然还挺有一致性的,考虑到Matlab所有变量都是默认数组。

1.3 字符(char) vs. 字符串(string)

所以,如果我们用class或者whos来查看一个字符串变量的类型,就有如下结果:

>> s1 = ['abc', 'efg']

s1 =

    'abcefg'

>> class(s1)

ans =

    'char'

可以看到,一行的字符数组会被自动连接在一起,因为字符数组行向量是其本质。以前的时候,我们甚至就是用这种方式来进行字符串的拼接的。

>> s1'

ans =

  6×1 char 数组

    'a'
    'b'
    'c'
    'e'
    'f'
    'g'

而对于字符串数组,就不会这样了。

>> s2 = ["abcd", "efg"]

s2 =

  1×2 string 数组

    "abcd"    "efg"

>> class(s2)

ans =

    'string'

大部分处理字符串的函数都可以对这两个类型进行操作,例如strcatstrfind, strsplitreplace等等。这些函数总是优先返回字符数组。

1.4 格式化字符串

对于其它语言中常见的格式化字符串,Matlab中也有,sprintf函数。

a = 1;
b = 2;
c = 3;
s = sprintf('a = %d, b = %d, c = %d', a, b, c);
disp(s);
a = 1, b = 2, c = 3

2016a之后,Matlab又增加了一个compose函数,用来格式化字符串,这个函数对字符串和字符数组都适用,结果略有不同。可以通过帮助和文档查看具体的用法。

>> compose('%f', rand(3))

ans =

  3×3 cell 数组

    {'0.278276'}    {'0.188147'}    {'0.088258'}
    {'0.303205'}    {'0.201239'}    {'0.414290'}
    {'0.284297'}    {'0.584602'}    {'0.494232'}

>> compose("%f", rand(3))

ans = 

  3×3 string 数组

    "0.074644"    "0.262734"    "0.416717"
    "0.442903"    "0.118222"    "0.030380"
    "0.637427"    "0.372898"    "0.547681"

2. 元胞数组

元胞数组,类似于别的语言中的List,可以存放不同类型的数据,也可以存放不同大小的数据。

2.1 创建元胞数组

元胞数组的字面量,用{}来表示。

a = {1, 2, 3};

b = {1, 2, 3; 4, 5, 6};

元胞数组同样可以是多维的。

a = cell(2, 3, 4);

2.2 访问元胞数组

元胞数组提供了两种方式来访问元胞数组中的元素,一种是(),一种是{}()返回的是一个元胞数组,{}返回的是元胞数组中的元素。

a = {1, 2, 3};
b = a{1};
c = a(1);

disp(b);
disp(c);
 1

{[1]}

前者按照系统显示数组的约定,不显示[],后者{}中显示了[]。、

最后,元胞数组的列转换与数组是一致的,

a = {1, 2, 3};

a(:)
ans =

  3×1 cell 数组

    {[1]}
    {[2]}
    {[3]}

而相应的,{:}会带来跟在命令行一次输入所有的元素,并用逗号隔开一样的效果。

>> a{:}

ans =

     1


ans =

     2


ans =

     3

>> 1,2,3

ans =

     1


ans =

     2


ans =

     3

在这样的场景中可以作为右值对多个变量赋值。这与调用函数时,返回多个值的情况是一样的。

>> [x1,x2,x3] = a{:}

x1 =

     1


x2 =

     2


x3 =

     3

2.3 元胞数组作为左值

元胞数组作为左值时,可以用{}来赋值,也可以用()来赋值。

a = {1, 2, 3};

a{1} = rand(4);
a(2) = {rand(4)};
>> a

a =

  1×3 cell 数组

    {4×4 double}    {4×4 double}    {[3]}

当然,跟前面的[x1,x2,x3] = a{:}一样,也可以用{:}来赋值。

a = {1, 2, 3};

[a{:}] = deal(rand(4));
>> a

a =

  1×3 cell 数组

    {4×4 double}    {4×4 double}    {4×4 double}

这个deal函数,是用来将一个值赋给多个变量的,这个函数在处理多个输出参数的时候,也是很有用的。它的参数可以是一个,此时就会拷贝到所有的输出上;也可以是多个,此时就会按照顺序赋值,要求两边逗号列表的元素个数相等。

例如:

a = {1, 2, 3};

[a{:}] = deal(1, 2, 3);
>> a

a =

  1×3 cell 数组

    {[1]}    {[2]}    {[3]} 

这就相当于[a{1}, a{2}, a{3}] = deal(1, 2, 3)

而采用()来访问,语义上会更简单,就是元胞数组的拷贝(右边为一个元素的元胞数组)或者逐个替换(左值和右值为长度相同的元胞数组)。

3. 结论

  1. Matlab中的字符串类型是string,字符串数组的字面量是"",字符数组的字面量是''
  2. Matlab中的元胞数组是一种特殊的数组,可以存放任意类型的数据,也可以存放不同类型的数据。
  3. 通过{:}可以得到一个逗号分开的列表。
  4. deal函数,可以用来将一个值赋给多个变量,也可以用来将多个值赋给多个变量。
04-03 14:49