%!test %! str = "1, 2, 3, 4\n 5, , , 8\n 9, 10, 11, 12"; %! fmtstr = "%f %d %f %s"; %! c = textscan (str, fmtstr, 2, "delimiter", ",", "emptyvalue", -Inf); %! assert (isequal (c{1}, [1;5])); %! assert (length (c{1}), 2); %! assert (iscellstr (c{4})); %! assert (isequal (c{3}, [3; -Inf])); %!test %! b = [10:10:100]; %! b = [b; 8*b/5]; %! str = sprintf ("%g miles/hr = %g kilometers/hr\n", b); %! fmt = "%f miles/hr = %f kilometers/hr"; %! c = textscan (str, fmt); %! assert (c{1}, b(1,:)', 1e-5); %! assert (c{2}, b(2,:)', 1e-5); %!test %! str = "13, -, NA, str1, -25\r\n// Middle line\r\n36, na, 05, str3, 6"; %! a = textscan (str, "%d %n %f %s %n", "delimiter", ",", %! "treatAsEmpty", {"NA", "na", "-"},"commentStyle", "//"); %! assert (a{1}, int32 ([13; 36])); %! assert (a{2}, [NaN; NaN]); %! assert (a{3}, [NaN; 5]); %! assert (a{4}, {"str1"; "str3"}); %! assert (a{5}, [-25; 6]); %!test %! str = "Km:10 = hhhBjjj miles16hour\r\n"; %! str = [str "Km:15 = hhhJjjj miles241hour\r\n"]; %! str = [str "Km:2 = hhhRjjj miles3hour\r\n"]; %! str = [str "Km:25 = hhhZ\r\n"]; %! fmt = "Km:%d = hhh%1sjjj miles%dhour"; %! a = textscan (str, fmt, "delimiter", " "); %! assert (a{1}', int32 ([10 15 2 25])); %! assert (a{2}', {'B' 'J' 'R' 'Z'}); %! assert (a{3}', int32 ([16 241 3 0])); ## Test with default endofline parameter %!test %! c = textscan ("L1\nL2", "%s"); %! assert (c{:}, {"L1"; "L2"}); ## Test with endofline parameter set to "" (empty) - newline should be in word %!test %! c = textscan ("L1\nL2", "%s", "endofline", ""); %! assert (int8 (c{:}{:}), int8 ([ 76, 49, 10, 76, 50 ])); ### Matlab fails this test. A literal after a conversion is not a delimiter #%!test #%! ## No delimiters at all besides EOL. Skip fields, even empty fields #%! str = "Text1Text2Text\nTextText4Text\nText57Text"; #%! c = textscan (str, "Text%*dText%dText"); #%! assert (c{1}, int32 ([2; 4; 0])); ## CollectOutput test %!test %! b = [10:10:100]; %! b = [b; 8*b/5; 8*b*1000/5]; %! str = sprintf ("%g miles/hr = %g (%g) kilometers (meters)/hr\n", b); %! fmt = "%f miles%s %s %f (%f) kilometers %*s"; %! c = textscan (str, fmt, "collectoutput", 1); %! assert (size (c{3}), [10, 2]); %! assert (size (c{2}), [10, 2]); ## CollectOutput test with uneven column length files %!test %! b = [10:10:100]; %! b = [b; 8*b/5; 8*b*1000/5]; %! str = sprintf ("%g miles/hr = %g (%g) kilometers (meters)/hr\n", b); %! str = [str "110 miles/hr"]; %! fmt = "%f miles%s %s %f (%f) kilometers %*s"; %! c = textscan (str, fmt, "collectoutput", 1); %! assert (size (c{1}), [11, 1]); %! assert (size (c{3}), [11, 2]); %! assert (size (c{2}), [11, 2]); %! assert (c{3}(end), NaN); %! assert (c{2}{11, 1}, "/hr"); %! assert (isempty (c{2}{11, 2}), true); ## Double quoted string %!test %! str = 'First "the second called ""the middle""" third'; %! fmt = "%q"; %! c = textscan (str, fmt); %! assert (c{1}, {"First"; 'the second called "the middle"'; "third"}); ## Arbitrary character %!test %! c = textscan ("a first, \n second, third", "%s %c %11c", 'delimiter', ' ,'); %! assert (c{1}, {"a"; "ond"}); %! assert (c{2}, {"f"; "t"}); %! assert (c{3}, {"irst, \n sec"; "hird"}); ## Field width and non-standard delimiters %!test %! str = "12;34;123456789;7"; %! c = textscan (str, "%4d %4d", "delimiter", ";", "collectOutput", 1); %! assert (c, {[12 34; 1234 5678; 9 7]}); ## Field width and non-standard delimiters %!test %! str = "12;34;123456789;7"; %! c = textscan (str, "%4f %f", "delimiter", ";", "collectOutput", 1); %! assert (c, {[12 34; 1234 56789; 7 NaN]}); ## Ignore trailing delimiter, but use leading one %!test %! str = "12.234e+2,34, \n12345.789-9876j,78\n,10|3"; %! c = textscan (str, "%10.2f %f", "delimiter", ",", "collectOutput", 1, %! "expChars", "e|"); %! assert (c, {[1223 34; 12345.79-9876j 78; NaN 10000]}, 1e-6); %!test %! ## Multi-character delimiter %! str = "99end2 space88gap 4564"; %! c = textscan (str, "%d %s", "delimiter", {"end", "gap", "space"}); %! assert (c{1}, int32([99; 88])); %! assert (c{2}, {"2 "; "4564"}); ### Delimiters as part of literals, and following literals #%!test #%! str = "12 R&D & 7"; #%! c = textscan (str, "%f R&D %f", "delimiter", "&", "collectOutput", 1, "EmptyValue", -99); #%! assert (c, {[12 -99; 7 -99]}); # ### Delimiters as part of literals, and before literals #%!test #%! str = "12 & R&D 7"; #%! c = textscan (str, "%f R&D %f", "delimiter", "&", "collectOutput", 1); #%! assert (c, {[12 7]}); %!test %! ## Check number of lines read, not number of passes through format string %! f = tempname (); %! fid = fopen (f, "w+"); %! fprintf (fid, "1\n2\n3\n4\n5\n6"); %! fseek (fid, 0, "bof"); %! c = textscan (fid, "%f %f", 2); %! E = feof (fid); %! fclose (fid); %! unlink (f); %! assert (c, {1, 2}); %! assert (!E); %!test %! ## Check number of lines read, not number of passes through format string %! f = tempname (); %! fid = fopen (f, "w+"); %! fprintf (fid, "1\r\n2\r3\n4\r\n5\n6"); %! fseek (fid, 0, "bof"); %! c = textscan (fid, "%f %f", 4); %! fclose (fid); %! unlink (f); %! assert (c, {[1;3], [2;4]}) %!test %! ## Check number of lines read, with multiple delimiters %! f = tempname (); %! fid = fopen (f, "w+"); %! fprintf (fid, "1-\r\n-2\r3-\n-4\r\n5\n6"); %! fseek (fid, 0, "bof"); %! c = textscan (fid, "%f %f", 4, "delimiter", "-", "multipleDelimsAsOne", 1); %! fclose (fid); %! unlink (f); %! assert (c, {[1;3], [2;4]}) ## Test input validation %!error textscan () %!error textscan (single (40)) %!error textscan ({40}) %!error textscan ("Hello World", 2) #%!error [C, pos] = textscan ("Hello World") %!error textscan ("Hello World", '%s', 'EndOfLine', 3) %!error <'%z' is not a valid format specifier> textscan ("1.0", "%z"); %!error textscan ("1.0", "foo"); ## Test incomplete first data line %! R = textscan (['Empty1' char(10)], 'Empty%d %f'); %! assert (R{1}, int32 (1)); %! assert (isempty (R{2}), true); ## bug #37023 %!test %! data = textscan(" 1. 1 \n 2 3\n", '%f %f'); %! assert (data{1}, [1; 2], 1e-15); %! assert (data{2}, [1; 3], 1e-15); ## Whitespace test (bug #37333) using delimiter ";" %!test %! tc = []; %! tc{1, 1} = "C:/code;"; %! tc{1, end+1} = "C:/code/meas;"; %! tc{1, end+1} = " C:/code/sim;"; %! tc{1, end+1} = "C:/code/utils;"; %! string = [tc{:}]; %! c = textscan (string, "%s", "delimiter", ";"); %! for k = 1:max (numel (c{1}), numel (tc)) %! lh = c{1}{k}; %! rh = tc{k}; %! rh(rh == ";") = ""; %! rh = strtrim (rh); %! assert (strcmp (lh, rh)); %! end ## Whitespace test (bug #37333), adding multipleDelimsAsOne true arg %!test %! tc = []; %! tc{1, 1} = "C:/code;"; %! tc{1, end+1} = " C:/code/meas;"; %! tc{1, end+1} = "C:/code/sim;;"; %! tc{1, end+1} = "C:/code/utils;"; %! string = [tc{:}]; %! c = textscan (string, "%s", "delimiter", ";", "multipleDelimsAsOne", 1); %! for k = 1:max (numel (c{1}), numel (tc)) %! lh = c{1}{k}; %! rh = tc{k}; %! rh(rh == ";") = ""; %! rh = strtrim (rh); %! assert (strcmp (lh, rh)); %! end ## Whitespace test (bug #37333), adding multipleDelimsAsOne false arg %!test %! tc = []; %! tc{1, 1} = "C:/code;"; %! tc{1, end+1} = " C:/code/meas;"; %! tc{1, end+1} = "C:/code/sim;;"; %! tc{1, end+1} = ""; %! tc{1, end+1} = "C:/code/utils;"; %! string = [tc{:}]; %! c = textscan (string, "%s", "delimiter", ";", "multipleDelimsAsOne", 0); %! for k = 1:max (numel (c{1}), numel (tc)) %! lh = c{1}{k}; %! rh = tc{k}; %! rh(rh == ";") = ""; %! rh = strtrim (rh); %! assert (strcmp (lh, rh)); %! end ## Whitespace test (bug #37333) whitespace "" arg %!test %! tc = []; %! tc{1, 1} = "C:/code;"; %! tc{1, end+1} = " C:/code/meas;"; %! tc{1, end+1} = "C:/code/sim;"; %! tc{1, end+1} = "C:/code/utils;"; %! string = [tc{:}]; %! c = textscan (string, "%s", "delimiter", ";", "whitespace", ""); %! for k = 1:max (numel (c{1}), numel (tc)) %! lh = c{1}{k}; %! rh = tc{k}; %! rh(rh == ";") = ""; %! assert (strcmp (lh, rh)); %! end ## Whitespace test (bug #37333), whitespace " " arg %!test %! tc = []; %! tc{1, 1} = "C:/code;"; %! tc{1, end+1} = " C:/code/meas;"; %! tc{1, end+1} = "C:/code/sim;"; %! tc{1, end+1} = "C:/code/utils;"; %! string = [tc{:}]; %! c = textscan (string, "%s", "delimiter", ";", "whitespace", " "); %! for k = 1:max (numel (c{1}), numel (tc)) %! lh = c{1}{k}; %! rh = tc{k}; %! rh(rh == ";") = ""; %! rh = strtrim (rh); %! assert (strcmp (lh, rh)); %! end %!test %!## Test unfinished comment %! c = textscan ("1 2 /* half comment", "%n %u8", "CommentStyle", {"/*", "*/}); %! assert (c, {1, 2}); %!test %!## Test start of comment as string %! c = textscan ("1 / 2 // 3", "%n %s %u8", "CommentStyle", {"//"}); %! assert (c, {1, "/", 2}); ## Test reading from a real file %!test %! f = tempname (); %! fid = fopen (f, "w+"); %! d = rand (1, 4); %! fprintf (fid, " %f %f /* comment */ %f %f ", d); %! fseek (fid, 0, "bof"); %! A = textscan (fid, "%f %f", "CommentStyle", {"/*", "*/"}); %! E = feof (fid); %! fclose (fid); %! unlink (f); %! assert (A{1}, [d(1); d(3)], 1e-6); %! assert (A{2}, [d(2); d(4)], 1e-6); %! assert (E); ## Tests reading with empty format, should return proper nr of columns %!test %! f = tempname (); %! fid = fopen (f, "w+"); %! fprintf (fid, " 1 2 3 4\n5 6 7 8"); %! fseek (fid, 0, "bof"); %! A = textscan (fid, ""); %! E = feof (fid); %! fclose (fid); %! unlink (f); %! assert (A{1}, [1 ; 5], 1e-6); %! assert (A{2}, [2 ; 6], 1e-6); %! assert (A{3}, [3 ; 7], 1e-6); %! assert (A{4}, [4 ; 8], 1e-6); %! assert (E); ## Tests reading with empty format; empty fields & incomplete lower row %!test %! f = tempname (); %! fid = fopen (f, "w+"); %! fprintf (fid, " ,2,,4\n5,6"); %! fseek (fid, 0, "bof"); %! A = textscan (fid, "", "delimiter", ",", "EmptyValue", 999, "CollectOutput" , 1); %! fclose (fid); %! unlink (f); %! assert (A{1}, [999, 2, 999, 4; 5, 6, 999, 999], 1e-6); ## Error message tests %!test %! f = tempname (); %! fid = fopen (f, "w+"); %! msg1 = "textscan: 1 parameters given, but only 0 values"; %! try %! A = textscan (fid, "", "headerlines"); %! end_try_catch; %! assert (!feof (fid)); %! fclose (fid); %! unlink (f); %! assert (msg1, lasterr); %!test %! f = tempname (); %! fid = fopen (f, "w+"); %! msg1 = "textscan: HeaderLines must be numeric"; %! try %! A = textscan (fid, "", "headerlines", "hh"); %! end_try_catch; %! fclose (fid); %! unlink (f); %! assert (msg1, lasterr); %!test %! ## Skip headerlines %! A = textscan ("field 1 field2\n 1 2\n3 4", "", "headerlines", 1, "collectOutput", 1); %! assert (A, {[1 2; 3 4]}); %!test %! ## Skip headerlines with non-default EOL %! A = textscan ("field 1 field2\r 1 2\r3 4", "", "headerlines", 2, "collectOutput", 1, "EndOfLine", '\r'); %! assert (A, {[3 4]}); %!test %! f = tempname (); %! fid = fopen (f, "w+"); %! fprintf (fid,"some_string"); %! fseek (fid, 0, "bof"); %! msg1 = "textscan: EndOfLine must be at most one character or '\\r\\n'"; %! try %! A = textscan (fid, "%f", "EndOfLine", "\n\r"); %! end_try_catch; %! fclose (fid); %! unlink (f); %! assert (msg1, lasterr); %!test %! f = tempname (); %! fid = fopen (f, "w+"); %! fprintf (fid,"some_string"); %! fseek (fid, 0, "bof"); %! msg1 = "textscan: EndOfLine must be at most one character or '\\r\\n'"; %! try %! A = textscan (fid, "%f", "EndOfLine", 33); %! end_try_catch; %! fclose (fid); %! unlink (f); %! assert (msg1, lasterr); ## Bug #41824 %!test %! assert (textscan ("123", "", "whitespace", " "){:}, 123); ## Bug #42343-1, just test supplied emptyvalue %!test %! assert (textscan (",NaN", "", "delimiter", "," ,"emptyValue" ,Inf), {Inf, NaN}); ## Bug #42343-2, test padding with supplied emptyvalue %!test %! a = textscan (",1,,4\nInf, ,NaN", "", "delimiter", ",", "emptyvalue", -10); %! assert (cell2mat (a), [-10, 1, -10, 4; Inf, -10, NaN, -10]); ## Bug #42528 %!test %! assert (textscan ("1i", ""){1}, 0+1i); %! assert (cell2mat (textscan ("3, 2-4i, NaN\n -i, 1, 23.4+2.2i\n 1+1 1+1j", "", "delimiter", ",")), [3+0i, 2-4i, NaN+0i; 0-i, 1+0i, 23.4+2.2i; 1 1 1+1i]); %!test %! ## TreatAsEmpty %! C = textscan ("1,2,3,NN,5,6\n", "%d%d%d%f", "delimiter", ",", "TreatAsEmpty", "NN"); %! assert (C{3}(1), int32 (3)); %! assert (C{4}(1), NaN); ## MultipleDelimsAsOne %!test %! str = "11, 12, 13,, 15\n21,, 23, 24, 25\n,, 33, 34, 35"; %! C = textscan (str, "%f %f %f %f", "delimiter", ",", "multipledelimsasone", 1, "endofline", "\n"); %! assert (C{1}', [11, 21, 33]); %! assert (C{2}', [12, 23, 34]); %! assert (C{3}', [13, 24, 35]); %! assert (C{4}', [15, 25, NaN]); ## Bug #44750 %!test %! assert (textscan ("/home/foo/", "%s", "delimiter", "/", "MultipleDelimsAsOne", 1){1}, ... %! {"home"; "foo"}); ### Allow cuddling %sliteral but warn it is ambiguous #%!test #%! C = textscan ("abcxyz51\nxyz83\n##xyz101", "%s xyz %d"); #%! assert (C{1}([1 3]), {"abc"; "##"}); #%! assert (isempty (C{1}{2}), true); #%! assert (C{2}, int32([51; 83; 101])); ### Literals are not delimiters. ## Test for false positives in check for non-supported format specifiers %!test %! assert (textscan ("Total: 32.5 % (of cm values)", "Total: %f %% (of cm values)"){1}, 32.5, 1e-5); ## Test various forms of string format specifiers (bug #45712) %!test %! str = "14 :1 z:2 z:3 z:5 z:11"; %! C = textscan (str, "%f %s %*s %3s %*3s %f", "delimiter", ":"); %! assert (C, {14, {"1 z"}, {"3 z"}, 11}); %% Bit width, fixed width conv. specifiers %!test %! str2 = "123456789012345 "; %! str2 = [str2 str2 str2 str2 str2 str2 str2 str2]; %! str2 = [str2 "123456789.01234 1234567890.1234 12345.678901234 12345.678901234"]; %! pttrn = "%3u8%*s %5u16%*s %10u32%*s %15u64 %3d8%*s %5d16%*s %10d32%*s %15d64 %9f32%*s %14f64%*s %10.2f32%*s %12.2f64%*s"; %! C = textscan (str2, pttrn, "delimiter", " "); %! assert (C{1}, uint8 (123)); %! assert (C{2}, uint16 (12345)); %! assert (C{3}, uint32 (1234567890)); %! assert (C{4}, uint64 (123456789012345)); %! assert (C{5}, int8 (123)); %! assert (C{6}, int16 (12345)); %! assert (C{7}, int32 (1234567890)); %! assert (C{8}, int64 (123456789012345)); %! assert (C{9}, single (123456789), 1e-12); %! assert (C{10}, double (1234567890.123), 1e-15); %! assert (C{11}, single (12345.68), 1e-5); %! assert (C{12}, double (12345.68), 1e-11); %% Bit width, fixed width conv. specifiers -- check the right amount is left %!test %! str2 = "123456789012345 "; %! str2 = [str2 str2 "123456789.01234"]; %! pttrn = "%3u8 %5u16 %10u32 %3d8 %5d16 %10d32 %9f32 %9f"; %! C = textscan (str2, pttrn, "delimiter", " "); %! assert (C{1}, uint8 (123)); %! assert (C{2}, uint16 (45678)); %! assert (C{3}, uint32 (9012345)); %! assert (C{4}, int8 (123)); %! assert (C{5}, int16 (45678)); %! assert (C{6}, int32 (9012345)); %! assert (C{7}, single (123456789), 1e-12); %! assert (C{8}, double (0.01234), 1e-12); %!test %! C = textscan ("123.123", "%2f %3f %3f"); %! assert (C{1}, 12); %! assert (C{2}, 3.1, 1e-11); %! assert (C{3}, 23); %!test %! C = textscan ("123.123", "%3f %3f %3f"); %! assert (C{1}, 123); %! assert (C{2}, 0.12, 1e-11); %! assert (C{3}, 3); %!test %! C = textscan ("123.123", "%4f %3f"); %! assert (C{1}, 123); %! assert (C{2}, 123); %% field width interrupts exponent. (Matlab incorrectly gives [12, 2e12]) %!test %! assert (textscan ("12e12", "%4f"), {[120; 2]}); %! assert (textscan ("12e+12", "%5f"), {[120; 2]}); %! assert (textscan ("125e-12","%6f"), {[12.5; 2]}); %% %[] tests %% Plain [..] and *[..] %!test %! ar = "abcdefguvwxAny\nacegxyzTrailing\nJunk"; %! C = textscan (ar, "%[abcdefg] %*[uvwxyz] %s"); %! assert (C{1}, {"abcdefg"; "aceg"; ""}); %! assert (C{2}, {"Any"; "Trailing"; "Junk"}); %!test %! assert (textscan ("A2 B2 C3", "%*[ABC]%d", 3), {int32([2; 2; 3])}); %% [^..] and *[^..] %!test %! br = "abcdefguvwx1Any\nacegxyz2Trailing\n3Junk"; %! C = textscan (br, "%[abcdefg] %*[^0123456789] %s"); %! assert (C{1}, {"abcdefg"; "aceg"; ""}); %! assert (C{2}, {"1Any"; "2Trailing"; "3Junk"}); %% [..] and [^..] containing delimiters %!test %! cr = "ab cd efguv wx1Any\na ce gx yz2Trailing\n 3Junk"; %! C = textscan (cr, "%[ abcdefg] %*[^0123456789] %s", "delimiter", " \n", "whitespace", ""); %! assert (C{1}, {"ab cd efg"; "a ce g"; " "}); %! assert (C{2}, {"1Any"; "2Trailing"; "3Junk"}); %% Bug #36464 %!test %! assert (textscan ('1 2 3 4 5 6', "%*n%n%*[^\n]"){1}, 2); %% test %[]] and %[^]] %!test %! assert (textscan ('345]', "%*[123456]%[]]"){1}{1}, "]"); %! assert (textscan ('345]', "%*[^]]%s"){1}{1}, "]"); ## Needed tests: # 1. Check that it fails at an appropriate point # 3. Checks for %[...] and %[^...] # 4. Checks for file vs string # 5. Checks for mixing headerlines and comments # 7. Checks for ReturnOnError # 8. Checks for all types of invalid parameter # 9. Checks derived from searching the internet for "= textscan" ## Check of what Matlab does: # 1. mixing headerlines and comments (just skip lines, even if comments) # 2. Empty EndOfLine (acceptable) # 3. Complex NaN (NaN+0i. However 1+NaNi gives 1+NaNi) # 4. delimiters at the start of lines with "multiple delimiters as one" (delim merges with EOL. Without multiple...one, a trailing delimiter before a newline is ignored) # 5. If N not specified, are parameters still checked? #ToDO: # 1. Common skip whitespace for everything except %[...] and %[^...] # 2. Refactor octave_scan to separate integers from floating point? # 3. Fail when the first mismatch occurs. Tests for this # 4. Remove commented out code # 5. Treatment of missing final end-of-line -- unequal line lengths. # 6. String delimiter as multichar, not as list of delims. (Check Matlab.) # 7. Minimise duplication with scanf and printf? Use as basis for textread? # 8. List tests modified from textscan.m # 9. Profile