Strings and Character Arrays
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
Written against MATLAB R2026b. The string class and its functions need MATLAB, not GNU Octave 11.3.0, which has only character arrays: a double-quoted literal in Octave is still a char row vector. The sessions that show output below are therefore the character-vector ones, run in Octave 11.3.0 (output labelled as such; MATLAB’s layout may differ). Everything that uses a string is checked line by line against the R2026b documentation and is labelled "not run here".
There are two ways to represent text, and they coexist in every real program. A character vector, written 'plate', is the original MATLAB text type: a row of char elements. A string array, written "plate", arrived in R2016b with the string function; double-quoted literals followed in R2017a (confirmed from secondary sources, not stated on the current documentation pages). A string array holds whole pieces of text as elements, of varying length, with no padding. New code should use strings; character vectors remain everywhere in older code and in many function interfaces. The sections below cover both, how they differ, and how to move between them. Regular expressions are on Regular Expressions and Patterns, and the general array rules are on Matrices and Arrays.
String arrays and character vectors
"Hello, world" is a 1-by-1 string array (a string scalar) that stores 12 characters. 'Hello, world' is a 1-by-12 char array: each character is an element, so indexing and slicing work per character. A quote is written twice inside the matching delimiter: "They said, ""Welcome!"" and waved." and 'it''s'.
str = "Hello, world"; % string scalar, 1-by-1
chr = 'Hello, world'; % char vector, 1-by-12
class(str), class(chr) % "string" and "char"
size(str), size(chr) % [1 1] and [1 12]
names = ["Mercury","Gemini","Apollo"; "Skylab","Skylab B","ISS"];
size(names) % 2-by-3 string array
Not run here: the string class does not exist in Octave. Per the documentation, str is a 1-by-1 string and chr is a 1-by-12 character vector, and the string matrix names is 2-by-3, each element keeping its own length with no padding. The strlength of the matrix is [7 6 6; 6 8 3].
The practical split is:
| Aspect | String array ("...") |
Character vector ('...') |
|---|---|---|
Introduced |
R2016b ( |
The original text type |
Element |
One whole piece of text |
One character |
Several pieces of text |
One array, any lengths |
Cell array ( |
Number of characters |
|
|
Empty |
|
|
Missing value |
|
None (use |
Append |
|
Square brackets ( |
Typical home |
New code, text data, table variables |
File names in older code, single characters, legacy APIs |
Functions that accept character vectors also accept strings, and the reverse is true for the text functions, so most calls work either way. The documentation recommends strings for new code. Character vectors keep two real uses: representing data encoded as characters, where you want the characters as elements, and compatibility with older code and with interfaces that insist on char. Interfaces that accept only char (some older functions and classes) can be fed with convertStringsToChars or char, which are covered below.
Character vectors in practice
The next session runs in Octave 11.3.0. It shows the character-vector basics: indexing, concatenation with square brackets, doubled quotes, and the numeric codes under the characters.
chr = 'Hello, world';
class(chr), size(chr), length(chr)
seq = 'GCTAGAATCC';
seq(4:6)
seq2 = [seq 'ATTAGAAACC']
q = 'it''s'
double('Az')
char([72 105])
s = ['Hello' ' ' 'World']
Octave 11.3.0 output:
ans = char
ans =
1 12
ans = 12
ans = AGA
seq2 = GCTAGAATCCATTAGAAACC
q = it's
ans =
65 122
ans = Hi
s = Hello World
A character vector is a numeric row underneath, so double('Az') gives the character codes and char of those codes gives the text back. This is also why 'a' + 1 is the number 98 and not the text b: arithmetic on char gives a double. With a string, "a" + 1 is the text "a1" (the number is converted and appended), so + means something different for the two types.
Source: MATLAB documentation: double
Character matrices. Stacking character vectors with ; needs rows of the same length. In MATLAB a vertical concatenation of rows with different lengths is an error (the identifier is MATLAB:catenate:dimensionMismatch; not run here, wording varies by release). Octave pads such rows with blanks instead, so do not rely on it. Use char (or the older strvcat) to pad to a common width on purpose:
z = char('abc','de')
size(z)
Octave 11.3.0 output:
z =
abc
de
ans =
2 3
char('abc','de') is a 2-by-3 character matrix, the second row padded with one blank. strvcat does the same but drops empty inputs, and is listed as not recommended on its documentation page. A character matrix is the book-era way of holding several pieces of text; today the right container is a string array, and cellstr is the bridge to the cell-array form (see Cell Arrays).
Missing strings
A string array can hold a missing value, displayed <missing> and created with string(missing) or missing converted to a string. It is the text counterpart of NaN: it marks text that is not known, which differs from an empty string "" (known and empty). ismissing(str) finds missing elements. Like NaN, a missing string is not equal to anything, itself included, so == and strcmp return false for it, and isequal on two missing strings is false. strlength returns NaN for a missing element. Not run here; this follows the documentation of ismissing and missing, and the page "Test for Empty Strings and Missing Values" linked from the strings FAQ. Character vectors have no missing value. The wider treatment of missing data is on Missing Data.
Concatenation and length
The two types concatenate differently, and this is the most common source of surprise.
-
Square brackets on character vectors join them into a longer vector:
['Hello' 'World']is'HelloWorld'. -
Square brackets on strings build a bigger array:
["Hello" "World"]is a 1-by-2 string array, not one longer string. -
+on strings appends text:"Hello" + " " + "World"is"Hello World". A non-text operand that can be converted is converted:"temperature is " + 21.6667 + "C"gives"temperature is 21.6667C". -
strcatappends whether the inputs are strings or character vectors, but for character-vector inputs it removes trailing whitespace of each argument; for string and cell inputs it keeps it. -
appendis the documentation’s recommended function, because it treats string arrays, character vectors and cell arrays of character vectors consistently:append("Today's ",tempText).
The next session, run in Octave 11.3.0, shows the strcat whitespace rule for character vectors and for cells (the cell form keeps the blank):
strcat('a ', 'b')
strcat({'a '}, 'b')
Octave 11.3.0 output:
ans = ab
ans =
{
[1,1] = a b
}
Length. length(str) of a string scalar is always 1, because it counts elements; strlength(str) counts characters. length returns the size of the longest dimension, so for a string array it is a number of strings. strlength also works on character vectors and on cell arrays of character vectors, so it is the single safe choice when you do not know which type you were given. An empty string is not an empty array: isempty("") is false, size("") is [1 1], while isempty('') is true. The documentation’s recommended test for "no text" is strlength(x) == 0, which is right for both types.
str = "Hello World"; chr = 'Hello World';
length(str) % 1 (one element)
strlength(str) % 11
length(chr) % 11
strlength(chr) % 11
isempty("") % false (a 1-by-1 string)
isempty('') % true
strlength("") == 0 % true
Not run here. The same lines on a character vector (length, numel, isempty, size('')) were run in Octave 11.3.0 and gave 11, 11, 1 and 0 0.
The string functions
The text functions work on string arrays (and, with the same names, on character vectors and cell arrays of character vectors unless noted). Most return a result of the same type as their input. Each call below is checked against the reference page named in the Source line (not run here); the examples use a line of the sensors.csv log (columns Time, SensorID and Temperature) of the heatflow scenario.
label = "2026-01-15 10:00:30,S2,22.1";
parts = split(label, ",") % ["2026-01-15 10:00:30"; "S2"; "22.1"]
id = parts(2); value = str2double(parts(3));
joined = join(["Dirichlet","Neumann","Periodic"], ", ")
clean = strip(" plate ") % "plate"
padded = pad("S2", 6) % "S2 " (padded on the right)
up = upper("heat"); low = lower("FLOW");
swapped = replace("plate.csv", ".csv", ".json")
tf1 = contains(label, "S2") % true
tf2 = contains(label, "s2", IgnoreCase=true) % true
tf3 = startsWith(label, "2026-") % true
tf4 = endsWith(label, ["22.1","22.0"]) % true (any pattern)
inner = extractBetween(label, " ", ",") % "10:00:30"
longer = insertAfter("plate.json", "plate", "_v2") % "plate_v2.json"
backwards = reverse("abc") % "cba"
Not run here. The behaviour of each function:
| Call | What it does |
|---|---|
|
Splits at each delimiter; the pieces go down the first non-singleton dimension (a column for a scalar input). |
|
Combines the elements of a string array along a dimension, putting the delimiter between them. |
|
Removes leading and trailing whitespace; a second argument chooses the side ( |
|
Pads to at least n characters; the side and the padding character are optional arguments. |
|
Case conversion. Use |
|
Replaces every occurrence of |
|
True where the pattern occurs; |
|
True where the text begins or ends with a pattern; they take an array of patterns. |
|
Substring between two markers; |
|
Inserts text after a pattern; |
|
Reverses the characters of each string. |
|
Count occurrences, or delete them. |
Two rules apply across the family. First, the text and the patterns can each be a string array, a character vector or a cell array of character vectors, and the type of the result follows the text (the first argument), not the patterns: string text gives a string result. For character-vector text, some functions return a character vector (strip, upper, replace) and others a cell array of character vectors (split, extractBetween), so check the reference page when the exact output type matters. Second, a missing string flows through as missing rather than raising an error. Not run here.
Source: MATLAB documentation: split, MATLAB documentation: join, MATLAB documentation: strip, MATLAB documentation: pad, MATLAB documentation: replace, MATLAB documentation: contains, MATLAB documentation: startsWith, MATLAB documentation: extractBetween, MATLAB documentation: insertAfter, MATLAB documentation: reverse
The character-vector equivalents are available in every release. This session ran in Octave 11.3.0 on the same CSV line:
label = '2026-01-15 10:00:30,S2,22.1';
parts = strsplit(label, ',')
strjoin({'a','b','c'}, ', ')
strtrim(sprintf(' padded \t\n'))
upper('heat'), lower('FLOW')
strrep('plate.csv', '.csv', '.json')
strfind('abcabc', 'bc')
idx = strfind(label, ',');
label(idx(1)+1:idx(2)-1)
fliplr('abc')
Octave 11.3.0 output:
parts =
{
[1,1] = 2026-01-15 10:00:30
[1,2] = S2
[1,3] = 22.1
}
ans = a, b, c
ans = padded
ans = HEAT
ans = flow
ans = plate.json
ans =
2 5
ans = S2
ans = cba
strsplit returns a cell array of character vectors, strjoin takes one, strtrim removes surrounding whitespace, strrep replaces substrings and strfind returns the start indices of every match. Each of these accepts strings in MATLAB. fliplr reverses any row vector, which is how a character vector was reversed before reverse existed.
Formatting text: sprintf, compose and format specifiers
sprintf turns data into text under the control of a format. It returns a character vector, whereas compose returns a string array and applies a format to each row of its input. The functions that take a format are compose, num2str, sprintf, fprintf and the error functions assert, error, warning and MException, so one set of rules serves display, files and messages. The syntax lines are:
txt = sprintf(formatSpec, A1, ..., An) str = compose(formatSpec, A) fprintf(formatSpec, A1, ..., An)
A formatting operator starts with %. Its fields, from left to right, are an optional numeric identifier, flags, field width, precision, subtype and the conversion character, which is the only required field.
| Conversion | Meaning |
|---|---|
|
Signed decimal integer. A non-integer value makes MATLAB switch to exponential or fixed notation (Octave printed |
|
Fixed-point notation, six decimals by default. |
|
Exponential notation with a lowercase or uppercase |
|
The more compact of |
|
Text; also a string array element. |
|
A single character. |
|
Octal, hexadecimal (lowercase, uppercase) and unsigned decimal notation. The subtype |
The flags are - (left-justify), + (always print a sign; for text, right-justify), a space (insert a blank before the value), 0 (pad with zeros) and # (alternate forms, such as the 0x prefix). The width is the minimum number of characters; the precision follows a period (digits after the point for %f and %e, significant digits for %g; for %s it truncates the text). A numeric identifier such as %2$s takes an argument out of order. Special characters in the format are written with escape sequences such as \n and \t; a literal percent sign is %%. sprintf translates escape sequences in its format, so sprintf("a\nb") and sprintf('a\nb') both contain a line break, whereas a plain double-quoted literal "a\nb" keeps the backslash (not run here). Use newline for a portable line break in a string.
The session below was run in Octave 11.3.0 with the format examples from the documentation page:
A = pi*ones(1,3);
txt = sprintf('%f | %.2f | %12f', A)
sprintf('%d %f %e %X', 46*ones(1,4))
sprintf('%g %.2g %f %.2f', pi*50*ones(1,4))
sprintf('right-justify: %12.2f\nleft-justify: %-12.2f|', 12.3, 12.3)
sprintf('sign: %+12.2f', 12.3)
sprintf('Pad with zeros: %012.2f', 5.2)
sprintf('%s has %d nodes', 'plate', 120)
sprintf('%d,', [1 2 3])
sprintf('%d %s', 1, 'a', 2, 'b')
sprintf('%c%c%c', 72, 105, 33)
sprintf('%5.1f%%', 99.5)
Octave 11.3.0 output:
txt = 3.141593 | 3.14 | 3.141593
ans = 46 46.000000 4.600000e+01 2E
ans = 157.08 1.6e+02 157.079633 157.08
ans = right-justify: 12.30
left-justify: 12.30 |
ans = sign: +12.30
ans = Pad with zeros: 000000005.20
ans = plate has 120 nodes
ans = 1,2,3,
ans = 1 a2 b
ans = Hi!
ans = 99.5%
Three behaviours follow from the output. The format is reused until all the data is consumed ('%d,' with [1 2 3] prints three items), so one sprintf can render a whole vector. Data are taken in column order, and a number given to %s or a character given to %d is converted to its code or its text. Numbers that do not fit the operator, such as a fraction passed to %d, change the notation; choose %f or %g for non-integers.
compose is the string-array counterpart and is the one to use when the format and the data are arrays:
rows = compose("Node %d has temperature %.1f", [1 21.5; 2 22.0])
Not run here. Per the documentation, compose applies the format to each row of the numeric input and returns a string column, here "Node 1 has temperature 21.5" and "Node 2 has temperature 22.0".
Conversions
-
string(x)converts numbers,datetime,duration,categoricalandcharto strings;string(pi)is"3.1416", andstring(missing)is the missing string.strings(n,m)makes an empty string array. -
char(x)converts strings, cell arrays and numeric codes to a character array;char(["ab","cde"])is a 2-by-3 padded matrix, andchar([72 105])is'Hi'.convertStringsToCharsandconvertCharsToStringsconvert many arguments at once and are the tools for updating old interfaces. -
cellstr(x)converts a string array or a character matrix to a cell array of character vectors, removing trailing blanks of a character matrix. It is a legacy bridge: use it when an old function demands a cell array of character vectors. -
num2str(x)formats numbers as text, with a precision argument (num2str(pi,8)) or a format (num2str(x,'%10.5f'));int2strrounds first, andmat2strwrites a matrix as an expression that can be read back. -
str2double(s)parses text to a number and returnsNaNfor text it cannot parse, with no error. It accepts a string, a character vector or a cell array, and is the safe parser.str2numevaluates its argument (it callseval), so use it only on trusted text. -
isstring,ischar,iscellstrandisStringScalartest the type.
This session ran in Octave 11.3.0 (the string, strlength and compose calls are not run here):
num2str(pi), num2str(pi,8), num2str([1 2 3])
mat2str([1 2;3 4.5])
int2str(2.7)
str2double('3.14'), str2double('abc'), str2double({'1','x','2.5'})
cellstr(['ab ';'cde'])
char({'ab','cde'})
disp(['Total: ' num2str(42)])
Octave 11.3.0 output:
ans = 3.1416
ans = 3.1415927
ans = 1 2 3
ans = [1 2;3 4.5]
ans = 3
ans = 3.1400
ans = NaN
ans =
1.0000 NaN 2.5000
ans =
{
[1,1] = ab
[2,1] = cde
}
ans =
ab
cde
Total: 42
The bad parse str2double('abc') is NaN with no error, which is convenient for reading messy files and dangerous when the NaN is not checked afterwards. cellstr trimmed the padding blank of 'ab '.
Source: MATLAB documentation: num2str, MATLAB documentation: str2double, MATLAB documentation: cellstr, MATLAB documentation: mat2str, MATLAB documentation: convertCharsToStrings, MATLAB documentation: convertStringsToChars
The conversion between the numeric and the text view of the same data is covered further on Type Identification and Conversion.
Comparing text
For strings, == and ~= compare whole strings and return a logical array: "abc" == "abc" is true, and ["a","b"] == "a" is [true false] through implicit expansion (see Implicit Expansion and Compatible Sizes). A character vector on one side is treated as a string, so "abc" == 'abc' is true (not run here). The relational operators < and > also work on strings, and sort them alphabetically.
For character vectors, == is the numeric, element-by-element comparison of the character codes. It works only when both operands have the same size (or one is a scalar) and otherwise fails with MATLAB:sizeDimensionsMustMatch ("Arrays have incompatible sizes for this operation"; Octave words it nonconformant arguments). Even when the sizes agree the result is an array, so if 'abc' == 'abd' is false only because the condition needs every element true. Use a comparison function instead:
-
strcmp(a,b)is a case-sensitive whole-text comparison that returns one logical, or an array when one argument is a cell array (strcmp('Dirichlet',{'Dirichlet','Neumann'})). It works on both types, and it does not raise an error for different lengths.isequalalso gives one answer. -
strcmpiignores case;strncmpandstrncmpicompare the first n characters. -
Use
contains,startsWithandendsWithto test for parts, andmatches(a string function) orstrcmpagainst a list for membership;ismember(text, list)also works.
strcmp('abc',{'abc','x','abc'})
strcmpi('ABC','abc')
strncmp('heatflow', 'heat', 4)
any(strcmp('Dirichlet', {'Dirichlet','Neumann'}))
Octave 11.3.0 output:
ans =
1 0 1
ans = 1
ans = 1
ans = 1
The MATLAB documentation’s recommended form for a conditional on text is if strcmp(kind, "Dirichlet") or, with a string scalar, if kind == "Dirichlet". Do not use == between character vectors of unknown length: if kind == 'Dirichlet' errors when kind has a different length, and gives a misleading answer when it has the same length and only some characters match.
Unicode and encodings
Text in MATLAB is Unicode. A char element is one UTF-16 code unit, so characters outside the basic plane (many emoji, for example) occupy two elements of a character vector, and length counts code units. Reading and writing files is where encodings matter: functions such as fopen, readlines, fileread and readtable take an encoding option, and files that are not UTF-8 need it stated. unicode2native converts text into the bytes of a named encoding and native2unicode converts bytes back to text; use them when talking to a binary protocol or a legacy file. Not run here; Octave 11.3.0 treats a char as a byte, which is a visible difference for non-ASCII text, so Octave results for such text should not be taken as MATLAB behaviour.
Legacy forms from the books
Older books show a character-vector toolkit. Some of it is still current and some is not recommended.
| Book-era form | Today |
|---|---|
|
Listed as not recommended in the R2026b documentation. Use |
|
Listed as not recommended. Use |
|
Not recommended. Use |
|
Still valid and accept strings. Prefer |
|
Building variable names in text. Use a cell array, a structure or a table instead (see Syntax, Statements and Variables). |
|
Still works for scalars. With strings, |
|
Fine for old interfaces; new code uses string arrays (the FAQ recommends against cell arrays of strings). |
The session ran in Octave 11.3.0:
strmatch('app', ['apple';'apply';'bears'])
findstr('abcabc','bc')
Octave 11.3.0 output (both calls first print an "obsolete" warning):
ans =
1
2
ans =
2 5
Pitfalls
-
lengthof a string is 1. Usestrlength. -
+between strings joins text, between character vectors adds numbers.'a' + 1is 98 and"a" + 1is"a1". -
Square brackets with strings make an array, not a longer string. Use
+,appendorstrcat. -
isempty("")is false. Teststrlength(x) == 0. -
==on character vectors is element-wise and needs equal sizes (MATLAB:sizeDimensionsMustMatch). Usestrcmp. -
Double quotes in command form.
cd "C:\Program Files"is an error because the quotes become part of the text; usecd('C:\Program Files')orcd 'C:\Program Files'(the FAQ shows the error text). -
Cell arrays of strings.
contains({"Venus","Earth"},"Earth")raises an error because most functions do not accept a cell array of strings; use a string array. -
strcatdrops trailing blanks of character vectors but not of strings or cells. -
str2doublereturnsNaNrather than an error for text that is not a number; check withisnan. -
str2numandevalrun code. Do not apply them to untrusted text. -
A missing string is not equal to itself, as
NaNis not. -
Octave differences. There is no
stringclass in Octave 11.3.0, a double-quoted literal is a character vector there, and vertical concatenation of unequal rows pads instead of failing; code that must run in both uses character vectors.
Where older books differ
The older MATLAB books present text only as character arrays: single quotes, [a b] concatenation, strcmp, strcat, strrep, findstr, strmatch, num2str, sprintf and eval-built strings, with cell arrays of character vectors for lists. The string class (R2016b) and double-quoted literals (R2017a) are absent, as are contains, startsWith, split, join, compose and the pattern objects of R2020b. The character-vector material is still correct; strmatch and findstr are the parts that are not recommended. Prefer string arrays in new code, and keep character vectors for single characters, data encoded as characters and old interfaces.