Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(416)

Side by Side Diff: book.html

Issue 12335109: Strings recipes for the Dart Cookbook (Closed) Base URL: https://github.com/dart-lang/cookbook.git@master
Patch Set: Made most changes requested my Kathy. Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « book.asciidoc ('k') | recipes/pubspec.lock » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
5 <meta name="generator" content="AsciiDoc 8.6.8">
6 <title>Dart Cookbook</title>
7 <style type="text/css">
8 /* Shared CSS for AsciiDoc xhtml11 and html5 backends */
9
10 /* Default font. */
11 body {
12 font-family: Georgia,serif;
13 }
14
15 /* Title font. */
16 h1, h2, h3, h4, h5, h6,
17 div.title, caption.title,
18 thead, p.table.header,
19 #toctitle,
20 #author, #revnumber, #revdate, #revremark,
21 #footer {
22 font-family: Arial,Helvetica,sans-serif;
23 }
24
25 body {
26 margin: 1em 5% 1em 5%;
27 }
28
29 a {
30 color: blue;
31 text-decoration: underline;
32 }
33 a:visited {
34 color: fuchsia;
35 }
36
37 em {
38 font-style: italic;
39 color: navy;
40 }
41
42 strong {
43 font-weight: bold;
44 color: #083194;
45 }
46
47 h1, h2, h3, h4, h5, h6 {
48 color: #527bbd;
49 margin-top: 1.2em;
50 margin-bottom: 0.5em;
51 line-height: 1.3;
52 }
53
54 h1, h2, h3 {
55 border-bottom: 2px solid silver;
56 }
57 h2 {
58 padding-top: 0.5em;
59 }
60 h3 {
61 float: left;
62 }
63 h3 + * {
64 clear: left;
65 }
66 h5 {
67 font-size: 1.0em;
68 }
69
70 div.sectionbody {
71 margin-left: 0;
72 }
73
74 hr {
75 border: 1px solid silver;
76 }
77
78 p {
79 margin-top: 0.5em;
80 margin-bottom: 0.5em;
81 }
82
83 ul, ol, li > p {
84 margin-top: 0;
85 }
86 ul > li { color: #aaa; }
87 ul > li > * { color: black; }
88
89 .monospaced, code, pre {
90 font-family: "Courier New", Courier, monospace;
91 font-size: inherit;
92 color: navy;
93 padding: 0;
94 margin: 0;
95 }
96
97
98 #author {
99 color: #527bbd;
100 font-weight: bold;
101 font-size: 1.1em;
102 }
103 #email {
104 }
105 #revnumber, #revdate, #revremark {
106 }
107
108 #footer {
109 font-size: small;
110 border-top: 2px solid silver;
111 padding-top: 0.5em;
112 margin-top: 4.0em;
113 }
114 #footer-text {
115 float: left;
116 padding-bottom: 0.5em;
117 }
118 #footer-badges {
119 float: right;
120 padding-bottom: 0.5em;
121 }
122
123 #preamble {
124 margin-top: 1.5em;
125 margin-bottom: 1.5em;
126 }
127 div.imageblock, div.exampleblock, div.verseblock,
128 div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
129 div.admonitionblock {
130 margin-top: 1.0em;
131 margin-bottom: 1.5em;
132 }
133 div.admonitionblock {
134 margin-top: 2.0em;
135 margin-bottom: 2.0em;
136 margin-right: 10%;
137 color: #606060;
138 }
139
140 div.content { /* Block element content. */
141 padding: 0;
142 }
143
144 /* Block element titles. */
145 div.title, caption.title {
146 color: #527bbd;
147 font-weight: bold;
148 text-align: left;
149 margin-top: 1.0em;
150 margin-bottom: 0.5em;
151 }
152 div.title + * {
153 margin-top: 0;
154 }
155
156 td div.title:first-child {
157 margin-top: 0.0em;
158 }
159 div.content div.title:first-child {
160 margin-top: 0.0em;
161 }
162 div.content + div.title {
163 margin-top: 0.0em;
164 }
165
166 div.sidebarblock > div.content {
167 background: #ffffee;
168 border: 1px solid #dddddd;
169 border-left: 4px solid #f0f0f0;
170 padding: 0.5em;
171 }
172
173 div.listingblock > div.content {
174 border: 1px solid #dddddd;
175 border-left: 5px solid #f0f0f0;
176 background: #f8f8f8;
177 padding: 0.5em;
178 }
179
180 div.quoteblock, div.verseblock {
181 padding-left: 1.0em;
182 margin-left: 1.0em;
183 margin-right: 10%;
184 border-left: 5px solid #f0f0f0;
185 color: #888;
186 }
187
188 div.quoteblock > div.attribution {
189 padding-top: 0.5em;
190 text-align: right;
191 }
192
193 div.verseblock > pre.content {
194 font-family: inherit;
195 font-size: inherit;
196 }
197 div.verseblock > div.attribution {
198 padding-top: 0.75em;
199 text-align: left;
200 }
201 /* DEPRECATED: Pre version 8.2.7 verse style literal block. */
202 div.verseblock + div.attribution {
203 text-align: left;
204 }
205
206 div.admonitionblock .icon {
207 vertical-align: top;
208 font-size: 1.1em;
209 font-weight: bold;
210 text-decoration: underline;
211 color: #527bbd;
212 padding-right: 0.5em;
213 }
214 div.admonitionblock td.content {
215 padding-left: 0.5em;
216 border-left: 3px solid #dddddd;
217 }
218
219 div.exampleblock > div.content {
220 border-left: 3px solid #dddddd;
221 padding-left: 0.5em;
222 }
223
224 div.imageblock div.content { padding-left: 0; }
225 span.image img { border-style: none; }
226 a.image:visited { color: white; }
227
228 dl {
229 margin-top: 0.8em;
230 margin-bottom: 0.8em;
231 }
232 dt {
233 margin-top: 0.5em;
234 margin-bottom: 0;
235 font-style: normal;
236 color: navy;
237 }
238 dd > *:first-child {
239 margin-top: 0.1em;
240 }
241
242 ul, ol {
243 list-style-position: outside;
244 }
245 ol.arabic {
246 list-style-type: decimal;
247 }
248 ol.loweralpha {
249 list-style-type: lower-alpha;
250 }
251 ol.upperalpha {
252 list-style-type: upper-alpha;
253 }
254 ol.lowerroman {
255 list-style-type: lower-roman;
256 }
257 ol.upperroman {
258 list-style-type: upper-roman;
259 }
260
261 div.compact ul, div.compact ol,
262 div.compact p, div.compact p,
263 div.compact div, div.compact div {
264 margin-top: 0.1em;
265 margin-bottom: 0.1em;
266 }
267
268 tfoot {
269 font-weight: bold;
270 }
271 td > div.verse {
272 white-space: pre;
273 }
274
275 div.hdlist {
276 margin-top: 0.8em;
277 margin-bottom: 0.8em;
278 }
279 div.hdlist tr {
280 padding-bottom: 15px;
281 }
282 dt.hdlist1.strong, td.hdlist1.strong {
283 font-weight: bold;
284 }
285 td.hdlist1 {
286 vertical-align: top;
287 font-style: normal;
288 padding-right: 0.8em;
289 color: navy;
290 }
291 td.hdlist2 {
292 vertical-align: top;
293 }
294 div.hdlist.compact tr {
295 margin: 0;
296 padding-bottom: 0;
297 }
298
299 .comment {
300 background: yellow;
301 }
302
303 .footnote, .footnoteref {
304 font-size: 0.8em;
305 }
306
307 span.footnote, span.footnoteref {
308 vertical-align: super;
309 }
310
311 #footnotes {
312 margin: 20px 0 20px 0;
313 padding: 7px 0 0 0;
314 }
315
316 #footnotes div.footnote {
317 margin: 0 0 5px 0;
318 }
319
320 #footnotes hr {
321 border: none;
322 border-top: 1px solid silver;
323 height: 1px;
324 text-align: left;
325 margin-left: 0;
326 width: 20%;
327 min-width: 100px;
328 }
329
330 div.colist td {
331 padding-right: 0.5em;
332 padding-bottom: 0.3em;
333 vertical-align: top;
334 }
335 div.colist td img {
336 margin-top: 0.3em;
337 }
338
339 @media print {
340 #footer-badges { display: none; }
341 }
342
343 #toc {
344 margin-bottom: 2.5em;
345 }
346
347 #toctitle {
348 color: #527bbd;
349 font-size: 1.1em;
350 font-weight: bold;
351 margin-top: 1.0em;
352 margin-bottom: 0.1em;
353 }
354
355 div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
356 margin-top: 0;
357 margin-bottom: 0;
358 }
359 div.toclevel2 {
360 margin-left: 2em;
361 font-size: 0.9em;
362 }
363 div.toclevel3 {
364 margin-left: 4em;
365 font-size: 0.9em;
366 }
367 div.toclevel4 {
368 margin-left: 6em;
369 font-size: 0.9em;
370 }
371
372 span.aqua { color: aqua; }
373 span.black { color: black; }
374 span.blue { color: blue; }
375 span.fuchsia { color: fuchsia; }
376 span.gray { color: gray; }
377 span.green { color: green; }
378 span.lime { color: lime; }
379 span.maroon { color: maroon; }
380 span.navy { color: navy; }
381 span.olive { color: olive; }
382 span.purple { color: purple; }
383 span.red { color: red; }
384 span.silver { color: silver; }
385 span.teal { color: teal; }
386 span.white { color: white; }
387 span.yellow { color: yellow; }
388
389 span.aqua-background { background: aqua; }
390 span.black-background { background: black; }
391 span.blue-background { background: blue; }
392 span.fuchsia-background { background: fuchsia; }
393 span.gray-background { background: gray; }
394 span.green-background { background: green; }
395 span.lime-background { background: lime; }
396 span.maroon-background { background: maroon; }
397 span.navy-background { background: navy; }
398 span.olive-background { background: olive; }
399 span.purple-background { background: purple; }
400 span.red-background { background: red; }
401 span.silver-background { background: silver; }
402 span.teal-background { background: teal; }
403 span.white-background { background: white; }
404 span.yellow-background { background: yellow; }
405
406 span.big { font-size: 2em; }
407 span.small { font-size: 0.6em; }
408
409 span.underline { text-decoration: underline; }
410 span.overline { text-decoration: overline; }
411 span.line-through { text-decoration: line-through; }
412
413 div.unbreakable { page-break-inside: avoid; }
414
415
416 /*
417 * xhtml11 specific
418 *
419 * */
420
421 div.tableblock {
422 margin-top: 1.0em;
423 margin-bottom: 1.5em;
424 }
425 div.tableblock > table {
426 border: 3px solid #527bbd;
427 }
428 thead, p.table.header {
429 font-weight: bold;
430 color: #527bbd;
431 }
432 p.table {
433 margin-top: 0;
434 }
435 /* Because the table frame attribute is overriden by CSS in most browsers. */
436 div.tableblock > table[frame="void"] {
437 border-style: none;
438 }
439 div.tableblock > table[frame="hsides"] {
440 border-left-style: none;
441 border-right-style: none;
442 }
443 div.tableblock > table[frame="vsides"] {
444 border-top-style: none;
445 border-bottom-style: none;
446 }
447
448
449 /*
450 * html5 specific
451 *
452 * */
453
454 table.tableblock {
455 margin-top: 1.0em;
456 margin-bottom: 1.5em;
457 }
458 thead, p.tableblock.header {
459 font-weight: bold;
460 color: #527bbd;
461 }
462 p.tableblock {
463 margin-top: 0;
464 }
465 table.tableblock {
466 border-width: 3px;
467 border-spacing: 0px;
468 border-style: solid;
469 border-color: #527bbd;
470 border-collapse: collapse;
471 }
472 th.tableblock, td.tableblock {
473 border-width: 1px;
474 padding: 4px;
475 border-style: solid;
476 border-color: #527bbd;
477 }
478
479 table.tableblock.frame-topbot {
480 border-left-style: hidden;
481 border-right-style: hidden;
482 }
483 table.tableblock.frame-sides {
484 border-top-style: hidden;
485 border-bottom-style: hidden;
486 }
487 table.tableblock.frame-none {
488 border-style: hidden;
489 }
490
491 th.tableblock.halign-left, td.tableblock.halign-left {
492 text-align: left;
493 }
494 th.tableblock.halign-center, td.tableblock.halign-center {
495 text-align: center;
496 }
497 th.tableblock.halign-right, td.tableblock.halign-right {
498 text-align: right;
499 }
500
501 th.tableblock.valign-top, td.tableblock.valign-top {
502 vertical-align: top;
503 }
504 th.tableblock.valign-middle, td.tableblock.valign-middle {
505 vertical-align: middle;
506 }
507 th.tableblock.valign-bottom, td.tableblock.valign-bottom {
508 vertical-align: bottom;
509 }
510
511
512 /*
513 * manpage specific
514 *
515 * */
516
517 body.manpage h1 {
518 padding-top: 0.5em;
519 padding-bottom: 0.5em;
520 border-top: 2px solid silver;
521 border-bottom: 2px solid silver;
522 }
523 body.manpage h2 {
524 border-style: none;
525 }
526 body.manpage div.sectionbody {
527 margin-left: 3em;
528 }
529
530 @media print {
531 body.manpage div#toc { display: none; }
532 }
533
534
535 </style>
536 <script type="text/javascript">
537 /*<![CDATA[*/
538 var asciidoc = { // Namespace.
539
540 /////////////////////////////////////////////////////////////////////
541 // Table Of Contents generator
542 /////////////////////////////////////////////////////////////////////
543
544 /* Author: Mihai Bazon, September 2002
545 * http://students.infoiasi.ro/~mishoo
546 *
547 * Table Of Content generator
548 * Version: 0.4
549 *
550 * Feel free to use this script under the terms of the GNU General Public
551 * License, as long as you do not remove or alter this notice.
552 */
553
554 /* modified by Troy D. Hanson, September 2006. License: GPL */
555 /* modified by Stuart Rackham, 2006, 2009. License: GPL */
556
557 // toclevels = 1..4.
558 toc: function (toclevels) {
559
560 function getText(el) {
561 var text = "";
562 for (var i = el.firstChild; i != null; i = i.nextSibling) {
563 if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
564 text += i.data;
565 else if (i.firstChild != null)
566 text += getText(i);
567 }
568 return text;
569 }
570
571 function TocEntry(el, text, toclevel) {
572 this.element = el;
573 this.text = text;
574 this.toclevel = toclevel;
575 }
576
577 function tocEntries(el, toclevels) {
578 var result = new Array;
579 var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
580 // Function that scans the DOM tree for header elements (the DOM2
581 // nodeIterator API would be a better technique but not supported by all
582 // browsers).
583 var iterate = function (el) {
584 for (var i = el.firstChild; i != null; i = i.nextSibling) {
585 if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
586 var mo = re.exec(i.tagName);
587 if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
588 result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
589 }
590 iterate(i);
591 }
592 }
593 }
594 iterate(el);
595 return result;
596 }
597
598 var toc = document.getElementById("toc");
599 if (!toc) {
600 return;
601 }
602
603 // Delete existing TOC entries in case we're reloading the TOC.
604 var tocEntriesToRemove = [];
605 var i;
606 for (i = 0; i < toc.childNodes.length; i++) {
607 var entry = toc.childNodes[i];
608 if (entry.nodeName.toLowerCase() == 'div'
609 && entry.getAttribute("class")
610 && entry.getAttribute("class").match(/^toclevel/))
611 tocEntriesToRemove.push(entry);
612 }
613 for (i = 0; i < tocEntriesToRemove.length; i++) {
614 toc.removeChild(tocEntriesToRemove[i]);
615 }
616
617 // Rebuild TOC entries.
618 var entries = tocEntries(document.getElementById("content"), toclevels);
619 for (var i = 0; i < entries.length; ++i) {
620 var entry = entries[i];
621 if (entry.element.id == "")
622 entry.element.id = "_toc_" + i;
623 var a = document.createElement("a");
624 a.href = "#" + entry.element.id;
625 a.appendChild(document.createTextNode(entry.text));
626 var div = document.createElement("div");
627 div.appendChild(a);
628 div.className = "toclevel" + entry.toclevel;
629 toc.appendChild(div);
630 }
631 if (entries.length == 0)
632 toc.parentNode.removeChild(toc);
633 },
634
635
636 /////////////////////////////////////////////////////////////////////
637 // Footnotes generator
638 /////////////////////////////////////////////////////////////////////
639
640 /* Based on footnote generation code from:
641 * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
642 */
643
644 footnotes: function () {
645 // Delete existing footnote entries in case we're reloading the footnodes.
646 var i;
647 var noteholder = document.getElementById("footnotes");
648 if (!noteholder) {
649 return;
650 }
651 var entriesToRemove = [];
652 for (i = 0; i < noteholder.childNodes.length; i++) {
653 var entry = noteholder.childNodes[i];
654 if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
655 entriesToRemove.push(entry);
656 }
657 for (i = 0; i < entriesToRemove.length; i++) {
658 noteholder.removeChild(entriesToRemove[i]);
659 }
660
661 // Rebuild footnote entries.
662 var cont = document.getElementById("content");
663 var spans = cont.getElementsByTagName("span");
664 var refs = {};
665 var n = 0;
666 for (i=0; i<spans.length; i++) {
667 if (spans[i].className == "footnote") {
668 n++;
669 var note = spans[i].getAttribute("data-note");
670 if (!note) {
671 // Use [\s\S] in place of . so multi-line matches work.
672 // Because JavaScript has no s (dotall) regex flag.
673 note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
674 spans[i].innerHTML =
675 "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
676 "' title='View footnote' class='footnote'>" + n + "</a>]";
677 spans[i].setAttribute("data-note", note);
678 }
679 noteholder.innerHTML +=
680 "<div class='footnote' id='_footnote_" + n + "'>" +
681 "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
682 n + "</a>. " + note + "</div>";
683 var id =spans[i].getAttribute("id");
684 if (id != null) refs["#"+id] = n;
685 }
686 }
687 if (n == 0)
688 noteholder.parentNode.removeChild(noteholder);
689 else {
690 // Process footnoterefs.
691 for (i=0; i<spans.length; i++) {
692 if (spans[i].className == "footnoteref") {
693 var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
694 href = href.match(/#.*/)[0]; // Because IE return full URL.
695 n = refs[href];
696 spans[i].innerHTML =
697 "[<a href='#_footnote_" + n +
698 "' title='View footnote' class='footnote'>" + n + "</a>]";
699 }
700 }
701 }
702 },
703
704 install: function(toclevels) {
705 var timerId;
706
707 function reinstall() {
708 asciidoc.footnotes();
709 if (toclevels) {
710 asciidoc.toc(toclevels);
711 }
712 }
713
714 function reinstallAndRemoveTimer() {
715 clearInterval(timerId);
716 reinstall();
717 }
718
719 timerId = setInterval(reinstall, 500);
720 if (document.addEventListener)
721 document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false );
722 else
723 window.onload = reinstallAndRemoveTimer;
724 }
725
726 }
727 asciidoc.install(2);
728 /*]]>*/
729 </script>
730 </head>
731 <body class="article">
732 <div id="header">
733 <h1>Dart Cookbook</h1>
734 <span id="author">Shailen Tuli</span><br>
735 <div id="toc">
736 <div id="toctitle">Table of Contents</div>
737 <noscript><p><b>JavaScript must be enabled in your browser to display the tabl e of contents.</b></p></noscript>
738 </div>
739 </div>
740 <div id="content">
741 <div class="sect1">
742 <h2 id="_strings">Strings</h2>
743 <div class="sectionbody">
744 <div class="sect2">
745 <h3 id="_concatenating_strings">Concatenating Strings</h3>
746 <div class="sect3">
747 <h4 id="_problem">Problem</h4>
748 <div class="paragraph"><p>You want to concatenate strings in Dart. You tried usi ng <span class="monospaced">+</span>, but that
749 resulted in an error.</p></div>
750 </div>
751 <div class="sect3">
752 <h4 id="_solution">Solution</h4>
753 <div class="paragraph"><p>Use adjacent string literals:</p></div>
754 <div class="listingblock">
755 <div class="content monospaced">
756 <pre>var fact = 'Dart' 'is' ' fun!'; // 'Dart is fun!'</pre>
757 </div></div>
758 </div>
759 <div class="sect3">
760 <h4 id="_discussion">Discussion</h4>
761 <div class="paragraph"><p>Adjacent literals work over multiple lines:</p></div>
762 <div class="listingblock">
763 <div class="content monospaced">
764 <pre>var fact = 'Dart'
765 'is'
766 'fun!'; // 'Dart is fun!'</pre>
767 </div></div>
768 <div class="paragraph"><p>They also work when using multiline strings:</p></div>
769 <div class="listingblock">
770 <div class="content monospaced">
771 <pre>var lunch = '''Peanut
772 butter'''
773 '''and
774 jelly'''; // 'Peanut\nbutter and\njelly'</pre>
775 </div></div>
776 <div class="paragraph"><p>You can concatenate adjacent single line literals with multiline
777 strings:</p></div>
778 <div class="listingblock">
779 <div class="content monospaced">
780 <pre>var funnyGuys = 'Dewey ' 'Cheatem'
781 ''' and
782 Howe'''; // 'Dewey Cheatem and\n Howe'</pre>
783 </div></div>
784 <div class="sect4">
785 <h5 id="_alternatives_to_adjacent_string_literals">Alternatives to adjacent stri ng literals</h5>
786 <div class="paragraph"><p>You can use the <span class="monospaced">concat()</spa n> method on a string to concatenate it to
787 another string:</p></div>
788 <div class="listingblock">
789 <div class="content monospaced">
790 <pre>var film = filmToWatch();
791 film = film.concat('\n'); // 'The Big Lebowski\n'</pre>
792 </div></div>
793 <div class="paragraph"><p>Because <span class="monospaced">concat()</span> creat es a new string every time it is invoked, a long
794 chain of <span class="monospaced">concat()</span> s can be expensive. Avoid thos e. Use a StringBuffer
795 instead (see <em>Incrementally building a string efficiently using a
796 StringBuffer</em>, below).</p></div>
797 <div class="paragraph"><p>Use <span class="monospaced">join()</span> to combine a sequence of strings:</p></div>
798 <div class="listingblock">
799 <div class="content monospaced">
800 <pre>var film = ['The', 'Big', 'Lebowski']).join(' '); // 'The Big Lebowski'</pr e>
801 </div></div>
802 <div class="paragraph"><p>You can also use string interpolation to concatenate s trings (see
803 <em>Interpolating expressions inside strings</em>, below).</p></div>
804 </div>
805 </div>
806 </div>
807 <div class="sect2">
808 <h3 id="_interpolating_expressions_inside_strings">Interpolating expressions ins ide strings</h3>
809 <div class="sect3">
810 <h4 id="_problem_2">Problem</h4>
811 <div class="paragraph"><p>You want to embed Dart code inside strings.</p></div>
812 </div>
813 <div class="sect3">
814 <h4 id="_solution_2">Solution</h4>
815 <div class="paragraph"><p>You can put the value of an expression inside a string by using
816 ${expression}.</p></div>
817 <div class="listingblock">
818 <div class="content monospaced">
819 <pre>var favFood = 'sushi';
820 var whatDoILove = 'I love ${favFood.toUpperCase()}'; // 'I love SUSHI'</pre>
821 </div></div>
822 <div class="paragraph"><p>You can skip the {} if the expression is an identifier :</p></div>
823 <div class="listingblock">
824 <div class="content monospaced">
825 <pre>var whatDoILove = 'I love $favFood'; // 'I love sushi'</pre>
826 </div></div>
827 </div>
828 <div class="sect3">
829 <h4 id="_discussion_2">Discussion</h4>
830 <div class="paragraph"><p>An interpolated string, <span class="monospaced">'stri ng ${expression}</span> is equivalent to the
831 concatenation of the strings <span class="monospaced">string</span> and <span cl ass="monospaced">expression.toString()</span>.
832 Consider this code:</p></div>
833 <div class="listingblock">
834 <div class="content monospaced">
835 <pre>var four = 4;
836 var seasons = 'The $four seasons'; // 'The 4 seasons'</pre>
837 </div></div>
838 <div class="paragraph"><p>This is functionally equivalent to the following:</p>< /div>
839 <div class="listingblock">
840 <div class="content monospaced">
841 <pre>var seasons = 'The '.concat(4.toString()).concat(' seasons');
842 // 'The 4 seasons'</pre>
843 </div></div>
844 <div class="paragraph"><p>You should consider implementing a <span class="monosp aced">toString()</span> method for user-defined
845 objects. Here&#8217;s what happens if you don&#8217;t:</p></div>
846 <div class="listingblock">
847 <div class="content monospaced">
848 <pre>class Point {
849 num x, y;
850 Point(this.x, this.y);
851 }
852
853 var point = new Point(3, 4);
854 print('Point: $point'); // "Point: Instance of 'Point'"</pre>
855 </div></div>
856 <div class="paragraph"><p>Probably not what you wanted. Here is the same example with an explicit
857 <span class="monospaced">toString()</span>:</p></div>
858 <div class="listingblock">
859 <div class="content monospaced">
860 <pre>class Point {
861 ...
862
863 String toString() =&gt; 'x: $x, y: $y';
864 }
865
866 print('Point: $point'); // 'Point: x: 3, y: 4'</pre>
867 </div></div>
868 </div>
869 </div>
870 <div class="sect2">
871 <h3 id="_handling_special_characters_within_strings">Handling special characters within strings</h3>
872 <div class="sect3">
873 <h4 id="_problem_3">Problem</h4>
874 <div class="paragraph"><p>You want to put newlines, dollar signs, or other speci al characters in strings.</p></div>
875 </div>
876 <div class="sect3">
877 <h4 id="_solution_3">Solution</h4>
878 <div class="paragraph"><p>Prefix special characters with a <span class="monospac ed">\</span>.</p></div>
879 <div class="listingblock">
880 <div class="content monospaced">
881 <pre> print(Wile\nCoyote');
882 // Wile
883 // Coyote</pre>
884 </div></div>
885 </div>
886 <div class="sect3">
887 <h4 id="_discussion_3">Discussion</h4>
888 <div class="paragraph"><p>Dart designates a few characters as special, and these can be escaped:</p></div>
889 <div class="ulist"><ul>
890 <li>
891 <p>
892 \n for newline, equivalent to \x0A.
893 </p>
894 </li>
895 <li>
896 <p>
897 \r for carriage return, equivalent to \x0D.
898 </p>
899 </li>
900 <li>
901 <p>
902 \f for form feed, equivalent to \x0C.
903 </p>
904 </li>
905 <li>
906 <p>
907 \b for backspace, equivalent to \x08.
908 </p>
909 </li>
910 <li>
911 <p>
912 \t for tab, equivalent to \x09.
913 </p>
914 </li>
915 <li>
916 <p>
917 \v for vertical tab, equivalent to \x0B.
918 </p>
919 </li>
920 </ul></div>
921 <div class="paragraph"><p>If you prefer, you can use <span class="monospaced">\x </span> or <span class="monospaced">\u</span> notation to indicate the special
922 character:</p></div>
923 <div class="listingblock">
924 <div class="content monospaced">
925 <pre>print('Wile\x0ACoyote'); // Same as print('Wile\nCoyote')
926 print('Wile\u000ACoyote'); // Same as print('Wile\nCoyote')</pre>
927 </div></div>
928 <div class="paragraph"><p>You can also use <span class="monospaced">\u{}</span> notation:</p></div>
929 <div class="listingblock">
930 <div class="content monospaced">
931 <pre>print('Wile\u{000A}Coyote'); // same as print('Wile\nCoyote')</pre>
932 </div></div>
933 <div class="paragraph"><p>You can also escape the <span class="monospaced">$</sp an> used in string interpolation:</p></div>
934 <div class="listingblock">
935 <div class="content monospaced">
936 <pre>var superGenius = 'Wile Coyote';
937 print('$superGenius and Road Runner'); // 'Wile Coyote and Road Runner'
938 print('\$superGenius and Road Runner'); // '$superGenius and Road Runner'</pre>
939 </div></div>
940 <div class="paragraph"><p>If you escape a non-special character, the <span class ="monospaced">\</span> is ignored:</p></div>
941 <div class="listingblock">
942 <div class="content monospaced">
943 <pre>print('Wile \E Coyote'); // 'Wile E Coyote'</pre>
944 </div></div>
945 </div>
946 </div>
947 <div class="sect2">
948 <h3 id="_incrementally_building_a_string_using_a_stringbuffer">Incrementally bui lding a string using a StringBuffer</h3>
949 <div class="sect3">
950 <h4 id="_problem_4">Problem</h4>
951 <div class="paragraph"><p>You want to collect string fragments and combine them in an efficient
952 manner.</p></div>
953 </div>
954 <div class="sect3">
955 <h4 id="_solution_4">Solution</h4>
956 <div class="paragraph"><p>Use a StringBuffer to programmatically generate a stri ng. Consider this code
957 below for assembling a series of urls from fragments:</p></div>
958 <div class="listingblock">
959 <div class="content monospaced">
960 <pre>var data = [{'scheme': 'https', 'domain': 'news.ycombinator.com'},
961 {'domain': 'www.google.com'},
962 {'domain': 'reddit.com', 'path': 'search', 'params': 'q=dart'}
963 ];
964
965 String assembleUrlsUsingStringBuffer(entries) {
966 StringBuffer sb = new StringBuffer();
967 for (final item in entries) {
968 sb.write(item['scheme'] != null ? item['scheme'] : 'http');
969 sb.write("://");
970 sb.write(item['domain']);
971 sb.write('/');
972 sb.write(item['path'] != null ? item['path'] : '');
973 if (item['params'] != null) {
974 sb.write('?');
975 sb.write(item['params']);
976 }
977 sb.write('\n');
978 }
979 return sb.toString();
980 }
981
982 // https://news.ycombinator.com/
983 // http://www.google.com/
984 // http://reddit.com/search?q=dart</pre>
985 </div></div>
986 <div class="paragraph"><p>A StringBuffer collects string fragments, but does not generate a new string
987 until <span class="monospaced">toString()</span> is called.</p></div>
988 </div>
989 <div class="sect3">
990 <h4 id="_discussion_4">Discussion</h4>
991 <div class="paragraph"><p>Using a StringBuffer is vastly more efficient than con catenating fragments
992 at each step: Consider this rewrite of the above code:</p></div>
993 <div class="listingblock">
994 <div class="content monospaced">
995 <pre>String assembleUrlsUsingConcat(entries) {
996 var urls = '';
997 for (final item in entries) {
998 urls = urls.concat(item['scheme'] != null ? item['scheme'] : 'http');
999 urls = urls.concat("://");
1000 urls = urls.concat(item['domain']);
1001 urls = urls.concat('/');
1002 urls = urls.concat(item['path'] != null ? item['path'] : '');
1003 if (item['params'] != null) {
1004 urls = urls.concat('?');
1005 urls = urls.concat(item['params']);
1006 }
1007 urls = urls.concat('\n');
1008 }
1009 return urls;
1010 }</pre>
1011 </div></div>
1012 <div class="paragraph"><p>This approach produces the exact same result, but incu rs the cost of
1013 joining strings multiple times.</p></div>
1014 <div class="paragraph"><p>See the <em>Concatenating Strings</em> recipe for a de scription of <span class="monospaced">concat()</span>.</p></div>
1015 <div class="sect4">
1016 <h5 id="_other_stringbuffer_methods">Other StringBuffer methods</h5>
1017 <div class="paragraph"><p>In addition to <span class="monospaced">write()</span> , the StringBuffer class provides methods to
1018 write a list of strings (<span class="monospaced">writeAll()</span>), write a nu merical character code
1019 (<span class="monospaced">writeCharCode()</span>), write with an added newline ( <span class="monospaced">writeln()</span>), and
1020 more. The example below shows how to use these methods:</p></div>
1021 <div class="listingblock">
1022 <div class="content monospaced">
1023 <pre>var sb = new StringBuffer();
1024 sb.writeln('The Beatles:');
1025 sb.writeAll(['John, ', 'Paul, ', 'George, and Ringo']);
1026 sb.writeCharCode(33); // charCode for '!'.
1027 var beatles = sb.toString(); // 'The Beatles:\nJohn, Paul, George, and Ringo!'</ pre>
1028 </div></div>
1029 </div>
1030 </div>
1031 </div>
1032 <div class="sect2">
1033 <h3 id="_determining_whether_a_string_is_empty">Determining whether a string is empty</h3>
1034 <div class="sect3">
1035 <h4 id="_problem_5">Problem</h4>
1036 <div class="paragraph"><p>You want to know whether a string is empty. You tried <span class="monospaced">if (string) {...}</span>, but
1037 that did not work.</p></div>
1038 </div>
1039 <div class="sect3">
1040 <h4 id="_solution_5">Solution</h4>
1041 <div class="paragraph"><p>Use <span class="monospaced">string.isEmpty</span>:</p ></div>
1042 <div class="listingblock">
1043 <div class="content monospaced">
1044 <pre>var emptyString = '';
1045 print(emptyString.isEmpty); // true</pre>
1046 </div></div>
1047 <div class="paragraph"><p>You can also just use <span class="monospaced">==</spa n>:</p></div>
1048 <div class="listingblock">
1049 <div class="content monospaced">
1050 <pre>if (string == '') {...} // True if string is empty.</pre>
1051 </div></div>
1052 <div class="paragraph"><p>A string with a space is not empty:</p></div>
1053 <div class="listingblock">
1054 <div class="content monospaced">
1055 <pre>var space = ' ';
1056 print(space.isEmpty); // false</pre>
1057 </div></div>
1058 </div>
1059 <div class="sect3">
1060 <h4 id="_discussion_5">Discussion</h4>
1061 <div class="paragraph"><p>Don&#8217;t use <span class="monospaced">if (string)</ span> to test the emptiness of a string. In Dart, all objects
1062 except the boolean true evaluate to false, so <span class="monospaced">if(string )</span> is always false. You
1063 will see a warning in the editor if you use an <em>if</em> statement with a non- boolean
1064 in checked mode.</p></div>
1065 </div>
1066 </div>
1067 <div class="sect2">
1068 <h3 id="_removing_leading_and_trailing_whitespace">Removing leading and trailing whitespace</h3>
1069 <div class="sect3">
1070 <h4 id="_problem_6">Problem</h4>
1071 <div class="paragraph"><p>You want to remove spaces, tabs, and other whitespace from the beginning and
1072 end of strings.</p></div>
1073 </div>
1074 <div class="sect3">
1075 <h4 id="_solution_6">Solution</h4>
1076 <div class="paragraph"><p>Use <span class="monospaced">string.trim()</span>:</p> </div>
1077 <div class="listingblock">
1078 <div class="content monospaced">
1079 <pre>var space = '\n\r\f\t\v'; // A variety of space characters.
1080 var string = '$space X $space';
1081 var newString = string.trim(); // 'X'</pre>
1082 </div></div>
1083 <div class="paragraph"><p>The String class has no methods to remove only leading or only trailing
1084 whitespace. You can always use a RegExp.</p></div>
1085 <div class="paragraph"><p>Remove only leading whitespace:</p></div>
1086 <div class="listingblock">
1087 <div class="content monospaced">
1088 <pre>var newString = string.replaceFirst(new RegExp(r'^\s+'), ''); // 'X \n\r\f\ t\v'</pre>
1089 </div></div>
1090 <div class="paragraph"><p>Remove only trailing whitespace:</p></div>
1091 <div class="listingblock">
1092 <div class="content monospaced">
1093 <pre>var newString = string.replaceFirst(new RegExp(r'\s+$'), ''); // '\n\r\f\t\ v X'</pre>
1094 </div></div>
1095 </div>
1096 </div>
1097 <div class="sect2">
1098 <h3 id="_changing_string_case">Changing string case</h3>
1099 <div class="sect3">
1100 <h4 id="_problem_7">Problem</h4>
1101 <div class="paragraph"><p>You want to change the case of strings.</p></div>
1102 </div>
1103 <div class="sect3">
1104 <h4 id="_solution_7">Solution</h4>
1105 <div class="paragraph"><p>Use String&#8217;s <span class="monospaced">toUpperCas e()</span> and <span class="monospaced">toLowerCase()</span> methods:</p></div>
1106 <div class="listingblock">
1107 <div class="content monospaced">
1108 <pre>var theOneILove = 'I love Lucy';
1109 theOneILove.toUpperCase(); // 'I LOVE LUCY!'
1110 theOneILove.toLowerCase(); // 'i love lucy!'
1111
1112 // Zeus in modern Greek.
1113 var zeus = '\u0394\u03af\u03b1\u03c2'; // 'Δίας'
1114 zeus.toUpperCase(); // 'ΔΊΑΣ'
1115
1116 var resume = '\u0052\u00e9\u0073\u0075\u006d\u00e9'; // 'Résumé'
1117 resume.toLowerCase(); // 'résumé'</pre>
1118 </div></div>
1119 <div class="paragraph"><p>The <span class="monospaced">toUpperCase()</span> and <span class="monospaced">toLowerCase()</span> methods don&#8217;t affect the cha racters of
1120 scripts such as Devanagri that don&#8217;t have distinct letter cases.</p></div>
1121 <div class="listingblock">
1122 <div class="content monospaced">
1123 <pre>var chickenKebab = '\u091a\u093f\u0915\u0928 \u0915\u092c\u093e\u092c';
1124 // 'चिकन कबाब' (in Devanagari)
1125 chickenKebab.toLowerCase(); // 'चिकन कबाब'
1126 chickenKebab.toUpperCase(); // 'चिकन कबाब'</pre>
1127 </div></div>
1128 <div class="paragraph"><p>If a character&#8217;s case does not change when using <span class="monospaced">toUpperCase()</span> and
1129 <span class="monospaced">toLowerCase()</span>, it is most likely because the cha racter only has one
1130 form.</p></div>
1131 </div>
1132 </div>
1133 <div class="sect2">
1134 <h3 id="_handling_extended_characters_that_are_composed_of_multiple_code_units"> Handling extended characters that are composed of multiple code units</h3>
1135 <div class="sect3">
1136 <h4 id="_problem_8">Problem</h4>
1137 <div class="paragraph"><p>You want to use emoticons and other special symbols th at don&#8217;t fit into 16
1138 bits. How can you create such strings and use them correctly in your code?</p></ div>
1139 </div>
1140 <div class="sect3">
1141 <h4 id="_solution_8">Solution</h4>
1142 <div class="paragraph"><p>You can create an extended character using <span class ="monospaced">'\u{}'</span> syntax:</p></div>
1143 <div class="listingblock">
1144 <div class="content monospaced">
1145 <pre>var clef = '\u{1F3BC}'; // 🎼</pre>
1146 </div></div>
1147 </div>
1148 <div class="sect3">
1149 <h4 id="_discussion_6">Discussion</h4>
1150 <div class="paragraph"><p>Most UTF-16 strings are stored as two-byte (16 bit) co de sequences.
1151 Since two bytes can only contain the 65,536 characters in the 0x0 to 0xFFFF
1152 range, a pair of strings is used to store values in the 0x10000 to 0x10FFFF
1153 range. These strings only have semantic meaning as a pair. Individually, they
1154 are invalid UTF-16 strings. The term <em>surrogate pair</em> is often used to
1155 describe these strings.</p></div>
1156 <div class="paragraph"><p>The clef glyph <span class="monospaced">'\u{1F3BC}'</s pan> is composed of the <span class="monospaced">'\uD83C'</span> and <span class ="monospaced">'\uDFBC'</span>
1157 surrogate pair.</p></div>
1158 <div class="paragraph"><p>You can get an extended string&#8217;s surrogate pair through its <span class="monospaced">codeUnits</span>
1159 property:</p></div>
1160 <div class="listingblock">
1161 <div class="content monospaced">
1162 <pre>clef.codeUnits.map((codeUnit) =&gt; codeUnit.toRadixString(16));
1163 // ['d83c', 'dfbc']</pre>
1164 </div></div>
1165 <div class="paragraph"><p>Accessing a surrogate pair member leads to errors, and you should avoid
1166 properties and methods that expose it:</p></div>
1167 <div class="listingblock">
1168 <div class="content monospaced">
1169 <pre>print('\ud83c'); // Error: '\ud83c' is not a valid string.
1170 print('\udfbc'); // Error: '\udfbc' is not a valid string either.
1171 clef.split()[1]; // Error: accessing half of a surrogate pair.
1172 print(clef[i];) // Again, error: accessing half of a surrogate pair.</pre>
1173 </div></div>
1174 <div class="paragraph"><p>When dealing with strings containing extended characte rs, you should use the
1175 <span class="monospaced">runes</span> getter.</p></div>
1176 <div class="paragraph"><p>To get the string&#8217;s length, use <span class="mon ospaced">string.runes.length</span>. Don&#8217;t use
1177 <span class="monospaced">string.length</span>:</p></div>
1178 <div class="listingblock">
1179 <div class="content monospaced">
1180 <pre>print(clef.runes.length); // 1
1181 print(clef.length); // 2
1182 print(clef.codeUnits.length); // 2</pre>
1183 </div></div>
1184 <div class="paragraph"><p>To get an individual character or its numeric equivale nt, index the rune list:</p></div>
1185 <div class="listingblock">
1186 <div class="content monospaced">
1187 <pre>print(clef.runes.toList()[0]); // 127932 ('\u{1F3BC}')</pre>
1188 </div></div>
1189 <div class="paragraph"><p>To get the string&#8217;s characters as a list, map th e string runes:</p></div>
1190 <div class="listingblock">
1191 <div class="content monospaced">
1192 <pre>var clef = '\u{1F3BC}'; // 🎼
1193 var title = '$clef list:'
1194 print(subject.runes.map((rune) =&gt; new String.fromCharCode(rune)).toList());
1195 // ['🎼', ' ', 'l', 'i', 's', 't', ':']</pre>
1196 </div></div>
1197 </div>
1198 </div>
1199 <div class="sect2">
1200 <h3 id="_converting_between_characters_and_numerical_codes">Converting between c haracters and numerical codes</h3>
1201 <div class="sect3">
1202 <h4 id="_problem_9">Problem</h4>
1203 <div class="paragraph"><p>You want to convert string characters into numerical c odes and vice versa.
1204 You want to do this because sometimes you need to compare characters in a string
1205 to numerical values coming from another source. Or, maybe you want to split a
1206 string and then operate on each character.</p></div>
1207 </div>
1208 <div class="sect3">
1209 <h4 id="_solution_9">Solution</h4>
1210 <div class="paragraph"><p>Use the <span class="monospaced">runes</span> getter t o get a string&#8217;s code points:</p></div>
1211 <div class="listingblock">
1212 <div class="content monospaced">
1213 <pre>'Dart'.runes.toList(); // [68, 97, 114, 116]
1214
1215 var smileyFace = '\u263A'; // ☺
1216 print(smileyFace.runes.toList()); // [9786], (equivalent to ['\u263A']).
1217
1218 var clef = '\u{1F3BC}'; // 🎼
1219 print(clef.runes.toList()); // [127932], (equivalent to ['\u{1F3BC}']).</p re>
1220 </div></div>
1221 <div class="paragraph"><p>Use <span class="monospaced">string.codeUnits</span> t o get a string&#8217;s UTF-16 code units:</p></div>
1222 <div class="listingblock">
1223 <div class="content monospaced">
1224 <pre>'Dart'.codeUnits.toList(); // [68, 97, 114, 116]
1225 smileyFace.codeUnits.toList(); // [9786]
1226 clef.codeUnits.toList(); // [55356, 57276]</pre>
1227 </div></div>
1228 <div class="sect4">
1229 <h5 id="_using_codeunitat_to_get_individual_code_units">Using codeUnitAt() to ge t individual code units</h5>
1230 <div class="paragraph"><p>To get the code unit at a particular index, use <span class="monospaced">codeUnitAt()</span>:</p></div>
1231 <div class="listingblock">
1232 <div class="content monospaced">
1233 <pre>'Dart'.codeUnitAt(0); // 68
1234 smileyFace.codeUnitAt(0); // 9786 (the decimal value of '\u263A')
1235 clef.codeUnitAt(0); // 55356 (does not represent a legal string)</pre>
1236 </div></div>
1237 </div>
1238 </div>
1239 <div class="sect3">
1240 <h4 id="_converting_numerical_codes_to_strings">Converting numerical codes to st rings</h4>
1241 <div class="paragraph"><p>You can generate a new string from numerical codes usi ng the factory
1242 <span class="monospaced">String.fromCharCodes(charCodes)</span>. You can pass ei ther runes or code units and
1243 <span class="monospaced">String.fromCharCodes(charCodes)</span> can tell the dif ference and do the right
1244 thing automatically:</p></div>
1245 <div class="listingblock">
1246 <div class="content monospaced">
1247 <pre>print(new String.fromCharCodes([68, 97, 114, 116])); // 'D art'
1248
1249 print(new String.fromCharCodes([73, 32, 9825, 32, 76, 117, 99, 121]));
1250 // 'I ♡ Lucy'
1251
1252 // Passing code units representing the surrogate pair.
1253 print(new String.fromCharCodes([55356, 57276])); // 🎼
1254
1255 // Passing runes.
1256 print(new String.fromCharCodes([127932])); // 🎼</pre>
1257 </div></div>
1258 <div class="paragraph"><p>You can use the <span class="monospaced">String.fromCh arCode()</span> factory to convert a single rune
1259 or code unit to a string:</p></div>
1260 <div class="listingblock">
1261 <div class="content monospaced">
1262 <pre>new String.fromCharCode(68); // 'D'
1263 new String.fromCharCode(9786); // ☺
1264 new String.fromCharCode(127932); // 🎼</pre>
1265 </div></div>
1266 <div class="paragraph"><p>Creating a string with only one half of a surrogate pa ir is permitted,
1267 but not recommended.</p></div>
1268 </div>
1269 </div>
1270 <div class="sect2">
1271 <h3 id="_calculating_the_length_of_a_string">Calculating the length of a string< /h3>
1272 <div class="sect3">
1273 <h4 id="_problem_10">Problem</h4>
1274 <div class="paragraph"><p>You want to get the length of a string, but are not su re how to calculate the
1275 length correctly when working with variable length Unicode characters.</p></div>
1276 </div>
1277 <div class="sect3">
1278 <h4 id="_solution_10">Solution</h4>
1279 <div class="paragraph"><p>Use <span class="monospaced">string.runes.length</span > to get the number of characters in a string.</p></div>
1280 <div class="listingblock">
1281 <div class="content monospaced">
1282 <pre>print('I love music'.runes.length); // 12</pre>
1283 </div></div>
1284 <div class="paragraph"><p>You can safely use <span class="monospaced">string.run es.length</span> to get the length of strings that
1285 contain extended characters:</p></div>
1286 <div class="listingblock">
1287 <div class="content monospaced">
1288 <pre>var clef = '\u{1F3BC}'; // 🎼
1289 var subject = '$clef list:'; //
1290 var music = 'I $hearts $clef'; // 'I ♡ 🎼 '
1291
1292 clef.runes.length; // 1
1293 music.runes.length // 5</pre>
1294 </div></div>
1295 </div>
1296 <div class="sect3">
1297 <h4 id="_discussion_7">Discussion</h4>
1298 <div class="paragraph"><p>You can directly use a string&#8217;s <span class="mon ospaced">length</span> property (minus <span class="monospaced">runes</span>). T his returns
1299 the string&#8217;s code unit length. Using <span class="monospaced">string.lengt h</span> produces the same length
1300 as <span class="monospaced">string.runes.length</span> for most unicode characte rs.</p></div>
1301 <div class="paragraph"><p>For extended characters, the code unit length is one m ore than the rune
1302 length:</p></div>
1303 <div class="listingblock">
1304 <div class="content monospaced">
1305 <pre>clef.length; // 2
1306
1307 var music = 'I $hearts $clef'; // 'I ♡ 🎼 '
1308 music.length; // 6</pre>
1309 </div></div>
1310 <div class="paragraph"><p>Unless you specifically need the code unit length of a string, use
1311 <span class="monospaced">string.runes.length</span>.</p></div>
1312 <div class="sect4">
1313 <h5 id="_working_with_combined_characters">Working with combined characters</h5>
1314 <div class="paragraph"><p>It is tempting to brush aside the complexity involved in dealing with runes and
1315 code units and base the length of the string on the number of characters it
1316 appears to have. Anyone can tell that <em>Dart</em> has four characters, and <em >Amelié</em>
1317 has six, right? Almost. The length of <em>Dart</em> is indeed four, but the leng th of
1318 <em>Amelié</em> depends on how that string was constructed:</p></div>
1319 <div class="listingblock">
1320 <div class="content monospaced">
1321 <pre>var name = 'Ameli\u00E9'; // 'Amelié'
1322 var anotherName = 'Ameli\u0065\u0301'; // 'Amelié'
1323 print(name.length); // 6
1324 print(anotherName.length); // 7</pre>
1325 </div></div>
1326 <div class="paragraph"><p>Both <span class="monospaced">name</span> and <span cl ass="monospaced">anotherName</span> return strings that look the same, but where
1327 the <em>é</em> is constructed using a different number of runes. This makes it
1328 impossible to know the length of these strings by just looking at them.</p></div >
1329 </div>
1330 </div>
1331 </div>
1332 <div class="sect2">
1333 <h3 id="_processing_a_string_one_character_at_a_time">Processing a string one ch aracter at a time</h3>
1334 <div class="sect3">
1335 <h4 id="_problem_11">Problem</h4>
1336 <div class="paragraph"><p>You want to do something with each character in a stri ng.</p></div>
1337 </div>
1338 <div class="sect3">
1339 <h4 id="_solution_11">Solution</h4>
1340 <div class="paragraph"><p>Map the results of calling <span class="monospaced">st ring.split('')</span>:</p></div>
1341 <div class="listingblock">
1342 <div class="content monospaced">
1343 <pre>var lang= 'Dart';
1344
1345 // ['*D*', '*a*', '*r*', '*t*']
1346 print(lang.split('').map((char) =&gt; '*${char}*').toList());
1347
1348 var smileyFace = '\u263A';
1349 var happy = 'I am $smileyFace';
1350 print(happy.split('')); // ['I', ' ', 'a', 'm', ' ', '☺']</pre>
1351 </div></div>
1352 <div class="paragraph"><p>Or, loop over the characters of a string:</p></div>
1353 <div class="listingblock">
1354 <div class="content monospaced">
1355 <pre>var list = [];
1356 for(var i = 0; i &lt; lang.length; i++) {
1357 list.add('*${lang[i]}*');
1358 }
1359
1360 print(list); // ['*D*', '*a*', '*r*', '*t*']</pre>
1361 </div></div>
1362 <div class="paragraph"><p>Or, map the string runes:</p></div>
1363 <div class="listingblock">
1364 <div class="content monospaced">
1365 <pre>// ['*D*', '*a*', '*r*', '*t*']
1366 var charList = "Dart".runes.map((rune) {
1367 return '*${new String.fromCharCode(rune)}*').toList();
1368 });
1369
1370 // [[73, 'I'], [32, ' '], [97, 'a'], [109, 'm'], [32, ' '], [9786, '☺']]
1371 var runeList = happy.runes.map((rune) {
1372 return [rune, new String.fromCharCode(rune)]).toList();
1373 });</pre>
1374 </div></div>
1375 <div class="paragraph"><p>When working with extended characters, you should alwa ys map the string runes.
1376 Don&#8217;t use <span class="monospaced">split('')</span> and avoid indexing an extended string. See the <em>Handling
1377 extended characters that are composed of multiple code units</em> recipe for
1378 special considerations when working with extended strings.</p></div>
1379 </div>
1380 </div>
1381 <div class="sect2">
1382 <h3 id="_splitting_a_string_into_substrings">Splitting a string into substrings< /h3>
1383 <div class="sect3">
1384 <h4 id="_problem_12">Problem</h4>
1385 <div class="paragraph"><p>You want to split a string into substrings using a del imiter or a pattern.</p></div>
1386 </div>
1387 <div class="sect3">
1388 <h4 id="_solution_12">Solution</h4>
1389 <div class="paragraph"><p>Use the <span class="monospaced">split()</span> method with a string or a RegExp as an argument.</p></div>
1390 <div class="listingblock">
1391 <div class="content monospaced">
1392 <pre>var smileyFace = '\u263A';
1393 var happy = 'I am $smileyFace';
1394 happy.split(' '); // ['I', 'am', '☺']</pre>
1395 </div></div>
1396 <div class="paragraph"><p>Here is an example of using <span class="monospaced">s plit()</span> with a RegExp:</p></div>
1397 <div class="listingblock">
1398 <div class="content monospaced">
1399 <pre>var nums = '2/7 3 4/5 3~/5';
1400 var numsRegExp = new RegExp(r'(\s|/|~/)');
1401 nums.split(numsRegExp); // ['2', '7', '3', '4', '5', '3', '5']</pre>
1402 </div></div>
1403 <div class="paragraph"><p>In the code above, the string <span class="monospaced" >nums</span> contains various numbers, some of which
1404 are expressed as fractions or as int-divisions. A RegExp splits the string to
1405 extract just the numbers.</p></div>
1406 <div class="paragraph"><p>You can perform operations on the matched and unmatche d portions of a string
1407 when using <span class="monospaced">split()</span> with a RegExp:</p></div>
1408 <div class="listingblock">
1409 <div class="content monospaced">
1410 <pre>var phrase = 'Eats SHOOTS leaves';
1411
1412 var newPhrase = phrase.splitMapJoin((new RegExp(r'SHOOTS')),
1413 onMatch: (m) =&gt; '*${m.group(0).toLowerCase()}*',
1414 onNonMatch: (n) =&gt; n.toUpperCase());
1415
1416 print(newPhrase); // 'EATS *shoots* LEAVES'</pre>
1417 </div></div>
1418 <div class="paragraph"><p>The RegExp matches the middle word (<em>SHOOTS</em>). A pair of callbacks are
1419 registered to transform the matched and unmatched substrings before the
1420 substrings are joined together again.</p></div>
1421 </div>
1422 </div>
1423 <div class="sect2">
1424 <h3 id="_determining_whether_a_string_contains_another_string">Determining wheth er a string contains another string</h3>
1425 <div class="sect3">
1426 <h4 id="_problem_13">Problem</h4>
1427 <div class="paragraph"><p>You want to find out whether a string is the substring of another string.</p></div>
1428 </div>
1429 <div class="sect3">
1430 <h4 id="_solution_13">Solution</h4>
1431 <div class="paragraph"><p>Use <span class="monospaced">string.contains()</span>: </p></div>
1432 <div class="listingblock">
1433 <div class="content monospaced">
1434 <pre>var fact = 'Dart strings are immutable';
1435 print(fact.contains('immutable')); // True.</pre>
1436 </div></div>
1437 <div class="paragraph"><p>You can use a second argument to specify where in the string to start looking:</p></div>
1438 <div class="listingblock">
1439 <div class="content monospaced">
1440 <pre>print(fact.contains('Dart', 2)); // False</pre>
1441 </div></div>
1442 </div>
1443 <div class="sect3">
1444 <h4 id="_discussion_8">Discussion</h4>
1445 <div class="paragraph"><p>The String class provides a couple of shortcuts for te sting whether a
1446 string is a substring of another:</p></div>
1447 <div class="listingblock">
1448 <div class="content monospaced">
1449 <pre>print(string.startsWith('Dart')); // True.
1450 print(string.endsWith('e')); // True.</pre>
1451 </div></div>
1452 <div class="paragraph"><p>You can also use <span class="monospaced">string.index Of()</span>, which returns -1 if the substring
1453 is not found within a string, and otherwise returns the matching index:</p></div >
1454 <div class="listingblock">
1455 <div class="content monospaced">
1456 <pre>var found = string.indexOf('art') != -1; // True, `art` is found in `Dart`. </pre>
1457 </div></div>
1458 <div class="paragraph"><p>You can also use a RegExp and <span class="monospaced" >hasMatch()</span>:</p></div>
1459 <div class="listingblock">
1460 <div class="content monospaced">
1461 <pre>var found = new RegExp(r'ar[et]').hasMatch(string);
1462 // True, 'art' and 'are' match.</pre>
1463 </div></div>
1464 </div>
1465 </div>
1466 <div class="sect2">
1467 <h3 id="_finding_matches_of_a_regexp_pattern_in_a_string">Finding matches of a R egExp pattern in a string</h3>
1468 <div class="sect3">
1469 <h4 id="_problem_14">Problem</h4>
1470 <div class="paragraph"><p>You want to use RegExp to match a pattern in a string, and want to be
1471 able to access the matches.</p></div>
1472 </div>
1473 <div class="sect3">
1474 <h4 id="_solution_14">Solution</h4>
1475 <div class="paragraph"><p>Construct a regular expression using the RegExp class, and find matches
1476 using the <span class="monospaced">allMatches()</span> method:</p></div>
1477 <div class="listingblock">
1478 <div class="content monospaced">
1479 <pre>var neverEatingThat = 'Not with a fox, not in a box';
1480 var regExp = new RegExp(r'[fb]ox');
1481 List matches = regExp.allMatches(neverEatingThat);
1482 print(matches.map((match) =&gt; match.group(0)).toList()); // ['fox', 'box']</pr e>
1483 </div></div>
1484 </div>
1485 <div class="sect3">
1486 <h4 id="_discussion_9">Discussion</h4>
1487 <div class="paragraph"><p>You can query the object returned by <span class="mono spaced">allMatches()</span> to find out the
1488 number of matches:</p></div>
1489 <div class="listingblock">
1490 <div class="content monospaced">
1491 <pre>var howManyMatches = matches.length; // 2</pre>
1492 </div></div>
1493 <div class="paragraph"><p>To find the first match, use <span class="monospaced"> firstMatch()</span>:</p></div>
1494 <div class="listingblock">
1495 <div class="content monospaced">
1496 <pre>var firstMatch = RegExp.firstMatch(neverEatingThat).group(0); // 'fox'</pre >
1497 </div></div>
1498 <div class="paragraph"><p>To directly get the matched string, use <span class="m onospaced">stringMatch()</span>:</p></div>
1499 <div class="listingblock">
1500 <div class="content monospaced">
1501 <pre>print(regExp.stringMatch(neverEatingThat)); // 'fox'
1502 print(regExp.stringMatch('I like bagels and lox')); // null</pre>
1503 </div></div>
1504 </div>
1505 </div>
1506 <div class="sect2">
1507 <h3 id="_substituting_strings_based_on_regexp_matches">Substituting strings base d on RegExp matches</h3>
1508 <div class="sect3">
1509 <h4 id="_problem_15">Problem</h4>
1510 <div class="paragraph"><p>You want to match substrings within a string and make substitutions
1511 based on the matches.</p></div>
1512 </div>
1513 <div class="sect3">
1514 <h4 id="_solution_15">Solution</h4>
1515 <div class="paragraph"><p>Construct a regular expression using the RegExp class and make
1516 replacements using <span class="monospaced">replaceAll()</span> method:</p></div >
1517 <div class="listingblock">
1518 <div class="content monospaced">
1519 <pre>var resume = 'resume'.replaceAll(new RegExp(r'e'), '\u00E9'); // 'résumé'</ pre>
1520 </div></div>
1521 <div class="paragraph"><p>If you want to replace just the first match, use <span class="monospaced">replaceFirst()</span>:</p></div>
1522 <div class="listingblock">
1523 <div class="content monospaced">
1524 <pre>// Replace the first match of one or more zeros with an empty string.
1525 var smallNum = '0.0001'.replaceFirst(new RegExp(r'0+'), ''); // '.0001'</pre>
1526 </div></div>
1527 <div class="paragraph"><p>You can use <span class="monospaced">replaceAllMatched ()</span> to register a function that modifies the
1528 matches:</p></div>
1529 <div class="listingblock">
1530 <div class="content monospaced">
1531 <pre>var heart = '\u2661'; // '♡'
1532 var string = 'I like Ike but I $heart Lucy';
1533 var regExp = new RegExp(r'[A-Z]\w+');
1534 var newString = string.replaceAllMapped(regExp, (match) {
1535 return match.group(0).toUpperCase()
1536 });
1537 print(newString); // 'I like IKE but I ♡ LUCY'</pre>
1538 </div></div>
1539 </div>
1540 </div>
1541 </div>
1542 </div>
1543 </div>
1544 <div id="footnotes"><hr></div>
1545 <div id="footer">
1546 <div id="footer-text">
1547 Last updated 2013-03-16 10:56:58 PDT
1548 </div>
1549 </div>
1550 </body>
1551 </html>
OLDNEW
« no previous file with comments | « book.asciidoc ('k') | recipes/pubspec.lock » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698