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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « book.asciidoc ('k') | recipes/pubspec.lock » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: book.html
diff --git a/book.html b/book.html
new file mode 100644
index 0000000000000000000000000000000000000000..7262a2b6c8e877083844b09743e01a78225cbf62
--- /dev/null
+++ b/book.html
@@ -0,0 +1,1551 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="generator" content="AsciiDoc 8.6.8">
+<title>Dart Cookbook</title>
+<style type="text/css">
+/* Shared CSS for AsciiDoc xhtml11 and html5 backends */
+
+/* Default font. */
+body {
+ font-family: Georgia,serif;
+}
+
+/* Title font. */
+h1, h2, h3, h4, h5, h6,
+div.title, caption.title,
+thead, p.table.header,
+#toctitle,
+#author, #revnumber, #revdate, #revremark,
+#footer {
+ font-family: Arial,Helvetica,sans-serif;
+}
+
+body {
+ margin: 1em 5% 1em 5%;
+}
+
+a {
+ color: blue;
+ text-decoration: underline;
+}
+a:visited {
+ color: fuchsia;
+}
+
+em {
+ font-style: italic;
+ color: navy;
+}
+
+strong {
+ font-weight: bold;
+ color: #083194;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: #527bbd;
+ margin-top: 1.2em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+}
+
+h1, h2, h3 {
+ border-bottom: 2px solid silver;
+}
+h2 {
+ padding-top: 0.5em;
+}
+h3 {
+ float: left;
+}
+h3 + * {
+ clear: left;
+}
+h5 {
+ font-size: 1.0em;
+}
+
+div.sectionbody {
+ margin-left: 0;
+}
+
+hr {
+ border: 1px solid silver;
+}
+
+p {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+}
+
+ul, ol, li > p {
+ margin-top: 0;
+}
+ul > li { color: #aaa; }
+ul > li > * { color: black; }
+
+.monospaced, code, pre {
+ font-family: "Courier New", Courier, monospace;
+ font-size: inherit;
+ color: navy;
+ padding: 0;
+ margin: 0;
+}
+
+
+#author {
+ color: #527bbd;
+ font-weight: bold;
+ font-size: 1.1em;
+}
+#email {
+}
+#revnumber, #revdate, #revremark {
+}
+
+#footer {
+ font-size: small;
+ border-top: 2px solid silver;
+ padding-top: 0.5em;
+ margin-top: 4.0em;
+}
+#footer-text {
+ float: left;
+ padding-bottom: 0.5em;
+}
+#footer-badges {
+ float: right;
+ padding-bottom: 0.5em;
+}
+
+#preamble {
+ margin-top: 1.5em;
+ margin-bottom: 1.5em;
+}
+div.imageblock, div.exampleblock, div.verseblock,
+div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
+div.admonitionblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.admonitionblock {
+ margin-top: 2.0em;
+ margin-bottom: 2.0em;
+ margin-right: 10%;
+ color: #606060;
+}
+
+div.content { /* Block element content. */
+ padding: 0;
+}
+
+/* Block element titles. */
+div.title, caption.title {
+ color: #527bbd;
+ font-weight: bold;
+ text-align: left;
+ margin-top: 1.0em;
+ margin-bottom: 0.5em;
+}
+div.title + * {
+ margin-top: 0;
+}
+
+td div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content div.title:first-child {
+ margin-top: 0.0em;
+}
+div.content + div.title {
+ margin-top: 0.0em;
+}
+
+div.sidebarblock > div.content {
+ background: #ffffee;
+ border: 1px solid #dddddd;
+ border-left: 4px solid #f0f0f0;
+ padding: 0.5em;
+}
+
+div.listingblock > div.content {
+ border: 1px solid #dddddd;
+ border-left: 5px solid #f0f0f0;
+ background: #f8f8f8;
+ padding: 0.5em;
+}
+
+div.quoteblock, div.verseblock {
+ padding-left: 1.0em;
+ margin-left: 1.0em;
+ margin-right: 10%;
+ border-left: 5px solid #f0f0f0;
+ color: #888;
+}
+
+div.quoteblock > div.attribution {
+ padding-top: 0.5em;
+ text-align: right;
+}
+
+div.verseblock > pre.content {
+ font-family: inherit;
+ font-size: inherit;
+}
+div.verseblock > div.attribution {
+ padding-top: 0.75em;
+ text-align: left;
+}
+/* DEPRECATED: Pre version 8.2.7 verse style literal block. */
+div.verseblock + div.attribution {
+ text-align: left;
+}
+
+div.admonitionblock .icon {
+ vertical-align: top;
+ font-size: 1.1em;
+ font-weight: bold;
+ text-decoration: underline;
+ color: #527bbd;
+ padding-right: 0.5em;
+}
+div.admonitionblock td.content {
+ padding-left: 0.5em;
+ border-left: 3px solid #dddddd;
+}
+
+div.exampleblock > div.content {
+ border-left: 3px solid #dddddd;
+ padding-left: 0.5em;
+}
+
+div.imageblock div.content { padding-left: 0; }
+span.image img { border-style: none; }
+a.image:visited { color: white; }
+
+dl {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+dt {
+ margin-top: 0.5em;
+ margin-bottom: 0;
+ font-style: normal;
+ color: navy;
+}
+dd > *:first-child {
+ margin-top: 0.1em;
+}
+
+ul, ol {
+ list-style-position: outside;
+}
+ol.arabic {
+ list-style-type: decimal;
+}
+ol.loweralpha {
+ list-style-type: lower-alpha;
+}
+ol.upperalpha {
+ list-style-type: upper-alpha;
+}
+ol.lowerroman {
+ list-style-type: lower-roman;
+}
+ol.upperroman {
+ list-style-type: upper-roman;
+}
+
+div.compact ul, div.compact ol,
+div.compact p, div.compact p,
+div.compact div, div.compact div {
+ margin-top: 0.1em;
+ margin-bottom: 0.1em;
+}
+
+tfoot {
+ font-weight: bold;
+}
+td > div.verse {
+ white-space: pre;
+}
+
+div.hdlist {
+ margin-top: 0.8em;
+ margin-bottom: 0.8em;
+}
+div.hdlist tr {
+ padding-bottom: 15px;
+}
+dt.hdlist1.strong, td.hdlist1.strong {
+ font-weight: bold;
+}
+td.hdlist1 {
+ vertical-align: top;
+ font-style: normal;
+ padding-right: 0.8em;
+ color: navy;
+}
+td.hdlist2 {
+ vertical-align: top;
+}
+div.hdlist.compact tr {
+ margin: 0;
+ padding-bottom: 0;
+}
+
+.comment {
+ background: yellow;
+}
+
+.footnote, .footnoteref {
+ font-size: 0.8em;
+}
+
+span.footnote, span.footnoteref {
+ vertical-align: super;
+}
+
+#footnotes {
+ margin: 20px 0 20px 0;
+ padding: 7px 0 0 0;
+}
+
+#footnotes div.footnote {
+ margin: 0 0 5px 0;
+}
+
+#footnotes hr {
+ border: none;
+ border-top: 1px solid silver;
+ height: 1px;
+ text-align: left;
+ margin-left: 0;
+ width: 20%;
+ min-width: 100px;
+}
+
+div.colist td {
+ padding-right: 0.5em;
+ padding-bottom: 0.3em;
+ vertical-align: top;
+}
+div.colist td img {
+ margin-top: 0.3em;
+}
+
+@media print {
+ #footer-badges { display: none; }
+}
+
+#toc {
+ margin-bottom: 2.5em;
+}
+
+#toctitle {
+ color: #527bbd;
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 1.0em;
+ margin-bottom: 0.1em;
+}
+
+div.toclevel0, div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+div.toclevel2 {
+ margin-left: 2em;
+ font-size: 0.9em;
+}
+div.toclevel3 {
+ margin-left: 4em;
+ font-size: 0.9em;
+}
+div.toclevel4 {
+ margin-left: 6em;
+ font-size: 0.9em;
+}
+
+span.aqua { color: aqua; }
+span.black { color: black; }
+span.blue { color: blue; }
+span.fuchsia { color: fuchsia; }
+span.gray { color: gray; }
+span.green { color: green; }
+span.lime { color: lime; }
+span.maroon { color: maroon; }
+span.navy { color: navy; }
+span.olive { color: olive; }
+span.purple { color: purple; }
+span.red { color: red; }
+span.silver { color: silver; }
+span.teal { color: teal; }
+span.white { color: white; }
+span.yellow { color: yellow; }
+
+span.aqua-background { background: aqua; }
+span.black-background { background: black; }
+span.blue-background { background: blue; }
+span.fuchsia-background { background: fuchsia; }
+span.gray-background { background: gray; }
+span.green-background { background: green; }
+span.lime-background { background: lime; }
+span.maroon-background { background: maroon; }
+span.navy-background { background: navy; }
+span.olive-background { background: olive; }
+span.purple-background { background: purple; }
+span.red-background { background: red; }
+span.silver-background { background: silver; }
+span.teal-background { background: teal; }
+span.white-background { background: white; }
+span.yellow-background { background: yellow; }
+
+span.big { font-size: 2em; }
+span.small { font-size: 0.6em; }
+
+span.underline { text-decoration: underline; }
+span.overline { text-decoration: overline; }
+span.line-through { text-decoration: line-through; }
+
+div.unbreakable { page-break-inside: avoid; }
+
+
+/*
+ * xhtml11 specific
+ *
+ * */
+
+div.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+div.tableblock > table {
+ border: 3px solid #527bbd;
+}
+thead, p.table.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.table {
+ margin-top: 0;
+}
+/* Because the table frame attribute is overriden by CSS in most browsers. */
+div.tableblock > table[frame="void"] {
+ border-style: none;
+}
+div.tableblock > table[frame="hsides"] {
+ border-left-style: none;
+ border-right-style: none;
+}
+div.tableblock > table[frame="vsides"] {
+ border-top-style: none;
+ border-bottom-style: none;
+}
+
+
+/*
+ * html5 specific
+ *
+ * */
+
+table.tableblock {
+ margin-top: 1.0em;
+ margin-bottom: 1.5em;
+}
+thead, p.tableblock.header {
+ font-weight: bold;
+ color: #527bbd;
+}
+p.tableblock {
+ margin-top: 0;
+}
+table.tableblock {
+ border-width: 3px;
+ border-spacing: 0px;
+ border-style: solid;
+ border-color: #527bbd;
+ border-collapse: collapse;
+}
+th.tableblock, td.tableblock {
+ border-width: 1px;
+ padding: 4px;
+ border-style: solid;
+ border-color: #527bbd;
+}
+
+table.tableblock.frame-topbot {
+ border-left-style: hidden;
+ border-right-style: hidden;
+}
+table.tableblock.frame-sides {
+ border-top-style: hidden;
+ border-bottom-style: hidden;
+}
+table.tableblock.frame-none {
+ border-style: hidden;
+}
+
+th.tableblock.halign-left, td.tableblock.halign-left {
+ text-align: left;
+}
+th.tableblock.halign-center, td.tableblock.halign-center {
+ text-align: center;
+}
+th.tableblock.halign-right, td.tableblock.halign-right {
+ text-align: right;
+}
+
+th.tableblock.valign-top, td.tableblock.valign-top {
+ vertical-align: top;
+}
+th.tableblock.valign-middle, td.tableblock.valign-middle {
+ vertical-align: middle;
+}
+th.tableblock.valign-bottom, td.tableblock.valign-bottom {
+ vertical-align: bottom;
+}
+
+
+/*
+ * manpage specific
+ *
+ * */
+
+body.manpage h1 {
+ padding-top: 0.5em;
+ padding-bottom: 0.5em;
+ border-top: 2px solid silver;
+ border-bottom: 2px solid silver;
+}
+body.manpage h2 {
+ border-style: none;
+}
+body.manpage div.sectionbody {
+ margin-left: 3em;
+}
+
+@media print {
+ body.manpage div#toc { display: none; }
+}
+
+
+</style>
+<script type="text/javascript">
+/*<![CDATA[*/
+var asciidoc = { // Namespace.
+
+/////////////////////////////////////////////////////////////////////
+// Table Of Contents generator
+/////////////////////////////////////////////////////////////////////
+
+/* Author: Mihai Bazon, September 2002
+ * http://students.infoiasi.ro/~mishoo
+ *
+ * Table Of Content generator
+ * Version: 0.4
+ *
+ * Feel free to use this script under the terms of the GNU General Public
+ * License, as long as you do not remove or alter this notice.
+ */
+
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
+ /* modified by Stuart Rackham, 2006, 2009. License: GPL */
+
+// toclevels = 1..4.
+toc: function (toclevels) {
+
+ function getText(el) {
+ var text = "";
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
+ text += i.data;
+ else if (i.firstChild != null)
+ text += getText(i);
+ }
+ return text;
+ }
+
+ function TocEntry(el, text, toclevel) {
+ this.element = el;
+ this.text = text;
+ this.toclevel = toclevel;
+ }
+
+ function tocEntries(el, toclevels) {
+ var result = new Array;
+ var re = new RegExp('[hH]([1-'+(toclevels+1)+'])');
+ // Function that scans the DOM tree for header elements (the DOM2
+ // nodeIterator API would be a better technique but not supported by all
+ // browsers).
+ var iterate = function (el) {
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
+ var mo = re.exec(i.tagName);
+ if (mo && (i.getAttribute("class") || i.getAttribute("className")) != "float") {
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
+ }
+ iterate(i);
+ }
+ }
+ }
+ iterate(el);
+ return result;
+ }
+
+ var toc = document.getElementById("toc");
+ if (!toc) {
+ return;
+ }
+
+ // Delete existing TOC entries in case we're reloading the TOC.
+ var tocEntriesToRemove = [];
+ var i;
+ for (i = 0; i < toc.childNodes.length; i++) {
+ var entry = toc.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div'
+ && entry.getAttribute("class")
+ && entry.getAttribute("class").match(/^toclevel/))
+ tocEntriesToRemove.push(entry);
+ }
+ for (i = 0; i < tocEntriesToRemove.length; i++) {
+ toc.removeChild(tocEntriesToRemove[i]);
+ }
+
+ // Rebuild TOC entries.
+ var entries = tocEntries(document.getElementById("content"), toclevels);
+ for (var i = 0; i < entries.length; ++i) {
+ var entry = entries[i];
+ if (entry.element.id == "")
+ entry.element.id = "_toc_" + i;
+ var a = document.createElement("a");
+ a.href = "#" + entry.element.id;
+ a.appendChild(document.createTextNode(entry.text));
+ var div = document.createElement("div");
+ div.appendChild(a);
+ div.className = "toclevel" + entry.toclevel;
+ toc.appendChild(div);
+ }
+ if (entries.length == 0)
+ toc.parentNode.removeChild(toc);
+},
+
+
+/////////////////////////////////////////////////////////////////////
+// Footnotes generator
+/////////////////////////////////////////////////////////////////////
+
+/* Based on footnote generation code from:
+ * http://www.brandspankingnew.net/archive/2005/07/format_footnote.html
+ */
+
+footnotes: function () {
+ // Delete existing footnote entries in case we're reloading the footnodes.
+ var i;
+ var noteholder = document.getElementById("footnotes");
+ if (!noteholder) {
+ return;
+ }
+ var entriesToRemove = [];
+ for (i = 0; i < noteholder.childNodes.length; i++) {
+ var entry = noteholder.childNodes[i];
+ if (entry.nodeName.toLowerCase() == 'div' && entry.getAttribute("class") == "footnote")
+ entriesToRemove.push(entry);
+ }
+ for (i = 0; i < entriesToRemove.length; i++) {
+ noteholder.removeChild(entriesToRemove[i]);
+ }
+
+ // Rebuild footnote entries.
+ var cont = document.getElementById("content");
+ var spans = cont.getElementsByTagName("span");
+ var refs = {};
+ var n = 0;
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnote") {
+ n++;
+ var note = spans[i].getAttribute("data-note");
+ if (!note) {
+ // Use [\s\S] in place of . so multi-line matches work.
+ // Because JavaScript has no s (dotall) regex flag.
+ note = spans[i].innerHTML.match(/\s*\[([\s\S]*)]\s*/)[1];
+ spans[i].innerHTML =
+ "[<a id='_footnoteref_" + n + "' href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ spans[i].setAttribute("data-note", note);
+ }
+ noteholder.innerHTML +=
+ "<div class='footnote' id='_footnote_" + n + "'>" +
+ "<a href='#_footnoteref_" + n + "' title='Return to text'>" +
+ n + "</a>. " + note + "</div>";
+ var id =spans[i].getAttribute("id");
+ if (id != null) refs["#"+id] = n;
+ }
+ }
+ if (n == 0)
+ noteholder.parentNode.removeChild(noteholder);
+ else {
+ // Process footnoterefs.
+ for (i=0; i<spans.length; i++) {
+ if (spans[i].className == "footnoteref") {
+ var href = spans[i].getElementsByTagName("a")[0].getAttribute("href");
+ href = href.match(/#.*/)[0]; // Because IE return full URL.
+ n = refs[href];
+ spans[i].innerHTML =
+ "[<a href='#_footnote_" + n +
+ "' title='View footnote' class='footnote'>" + n + "</a>]";
+ }
+ }
+ }
+},
+
+install: function(toclevels) {
+ var timerId;
+
+ function reinstall() {
+ asciidoc.footnotes();
+ if (toclevels) {
+ asciidoc.toc(toclevels);
+ }
+ }
+
+ function reinstallAndRemoveTimer() {
+ clearInterval(timerId);
+ reinstall();
+ }
+
+ timerId = setInterval(reinstall, 500);
+ if (document.addEventListener)
+ document.addEventListener("DOMContentLoaded", reinstallAndRemoveTimer, false);
+ else
+ window.onload = reinstallAndRemoveTimer;
+}
+
+}
+asciidoc.install(2);
+/*]]>*/
+</script>
+</head>
+<body class="article">
+<div id="header">
+<h1>Dart Cookbook</h1>
+<span id="author">Shailen Tuli</span><br>
+<div id="toc">
+ <div id="toctitle">Table of Contents</div>
+ <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
+</div>
+</div>
+<div id="content">
+<div class="sect1">
+<h2 id="_strings">Strings</h2>
+<div class="sectionbody">
+<div class="sect2">
+<h3 id="_concatenating_strings">Concatenating Strings</h3>
+<div class="sect3">
+<h4 id="_problem">Problem</h4>
+<div class="paragraph"><p>You want to concatenate strings in Dart. You tried using <span class="monospaced">+</span>, but that
+resulted in an error.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution">Solution</h4>
+<div class="paragraph"><p>Use adjacent string literals:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var fact = 'Dart' 'is' ' fun!'; // 'Dart is fun!'</pre>
+</div></div>
+</div>
+<div class="sect3">
+<h4 id="_discussion">Discussion</h4>
+<div class="paragraph"><p>Adjacent literals work over multiple lines:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var fact = 'Dart'
+'is'
+'fun!'; // 'Dart is fun!'</pre>
+</div></div>
+<div class="paragraph"><p>They also work when using multiline strings:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var lunch = '''Peanut
+butter'''
+'''and
+jelly'''; // 'Peanut\nbutter and\njelly'</pre>
+</div></div>
+<div class="paragraph"><p>You can concatenate adjacent single line literals with multiline
+strings:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var funnyGuys = 'Dewey ' 'Cheatem'
+''' and
+Howe'''; // 'Dewey Cheatem and\n Howe'</pre>
+</div></div>
+<div class="sect4">
+<h5 id="_alternatives_to_adjacent_string_literals">Alternatives to adjacent string literals</h5>
+<div class="paragraph"><p>You can use the <span class="monospaced">concat()</span> method on a string to concatenate it to
+another string:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var film = filmToWatch();
+film = film.concat('\n'); // 'The Big Lebowski\n'</pre>
+</div></div>
+<div class="paragraph"><p>Because <span class="monospaced">concat()</span> creates a new string every time it is invoked, a long
+chain of <span class="monospaced">concat()</span> s can be expensive. Avoid those. Use a StringBuffer
+instead (see <em>Incrementally building a string efficiently using a
+StringBuffer</em>, below).</p></div>
+<div class="paragraph"><p>Use <span class="monospaced">join()</span> to combine a sequence of strings:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var film = ['The', 'Big', 'Lebowski']).join(' '); // 'The Big Lebowski'</pre>
+</div></div>
+<div class="paragraph"><p>You can also use string interpolation to concatenate strings (see
+<em>Interpolating expressions inside strings</em>, below).</p></div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_interpolating_expressions_inside_strings">Interpolating expressions inside strings</h3>
+<div class="sect3">
+<h4 id="_problem_2">Problem</h4>
+<div class="paragraph"><p>You want to embed Dart code inside strings.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_2">Solution</h4>
+<div class="paragraph"><p>You can put the value of an expression inside a string by using
+${expression}.</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var favFood = 'sushi';
+var whatDoILove = 'I love ${favFood.toUpperCase()}'; // 'I love SUSHI'</pre>
+</div></div>
+<div class="paragraph"><p>You can skip the {} if the expression is an identifier:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var whatDoILove = 'I love $favFood'; // 'I love sushi'</pre>
+</div></div>
+</div>
+<div class="sect3">
+<h4 id="_discussion_2">Discussion</h4>
+<div class="paragraph"><p>An interpolated string, <span class="monospaced">'string ${expression}</span> is equivalent to the
+concatenation of the strings <span class="monospaced">string</span> and <span class="monospaced">expression.toString()</span>.
+Consider this code:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var four = 4;
+var seasons = 'The $four seasons'; // 'The 4 seasons'</pre>
+</div></div>
+<div class="paragraph"><p>This is functionally equivalent to the following:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var seasons = 'The '.concat(4.toString()).concat(' seasons');
+// 'The 4 seasons'</pre>
+</div></div>
+<div class="paragraph"><p>You should consider implementing a <span class="monospaced">toString()</span> method for user-defined
+objects. Here&#8217;s what happens if you don&#8217;t:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>class Point {
+ num x, y;
+ Point(this.x, this.y);
+}
+
+var point = new Point(3, 4);
+print('Point: $point'); // "Point: Instance of 'Point'"</pre>
+</div></div>
+<div class="paragraph"><p>Probably not what you wanted. Here is the same example with an explicit
+<span class="monospaced">toString()</span>:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>class Point {
+ ...
+
+ String toString() =&gt; 'x: $x, y: $y';
+}
+
+print('Point: $point'); // 'Point: x: 3, y: 4'</pre>
+</div></div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_handling_special_characters_within_strings">Handling special characters within strings</h3>
+<div class="sect3">
+<h4 id="_problem_3">Problem</h4>
+<div class="paragraph"><p>You want to put newlines, dollar signs, or other special characters in strings.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_3">Solution</h4>
+<div class="paragraph"><p>Prefix special characters with a <span class="monospaced">\</span>.</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre> print(Wile\nCoyote');
+ // Wile
+ // Coyote</pre>
+</div></div>
+</div>
+<div class="sect3">
+<h4 id="_discussion_3">Discussion</h4>
+<div class="paragraph"><p>Dart designates a few characters as special, and these can be escaped:</p></div>
+<div class="ulist"><ul>
+<li>
+<p>
+\n for newline, equivalent to \x0A.
+</p>
+</li>
+<li>
+<p>
+\r for carriage return, equivalent to \x0D.
+</p>
+</li>
+<li>
+<p>
+\f for form feed, equivalent to \x0C.
+</p>
+</li>
+<li>
+<p>
+\b for backspace, equivalent to \x08.
+</p>
+</li>
+<li>
+<p>
+\t for tab, equivalent to \x09.
+</p>
+</li>
+<li>
+<p>
+\v for vertical tab, equivalent to \x0B.
+</p>
+</li>
+</ul></div>
+<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
+character:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>print('Wile\x0ACoyote'); // Same as print('Wile\nCoyote')
+print('Wile\u000ACoyote'); // Same as print('Wile\nCoyote')</pre>
+</div></div>
+<div class="paragraph"><p>You can also use <span class="monospaced">\u{}</span> notation:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>print('Wile\u{000A}Coyote'); // same as print('Wile\nCoyote')</pre>
+</div></div>
+<div class="paragraph"><p>You can also escape the <span class="monospaced">$</span> used in string interpolation:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var superGenius = 'Wile Coyote';
+print('$superGenius and Road Runner'); // 'Wile Coyote and Road Runner'
+print('\$superGenius and Road Runner'); // '$superGenius and Road Runner'</pre>
+</div></div>
+<div class="paragraph"><p>If you escape a non-special character, the <span class="monospaced">\</span> is ignored:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>print('Wile \E Coyote'); // 'Wile E Coyote'</pre>
+</div></div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_incrementally_building_a_string_using_a_stringbuffer">Incrementally building a string using a StringBuffer</h3>
+<div class="sect3">
+<h4 id="_problem_4">Problem</h4>
+<div class="paragraph"><p>You want to collect string fragments and combine them in an efficient
+manner.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_4">Solution</h4>
+<div class="paragraph"><p>Use a StringBuffer to programmatically generate a string. Consider this code
+below for assembling a series of urls from fragments:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var data = [{'scheme': 'https', 'domain': 'news.ycombinator.com'},
+ {'domain': 'www.google.com'},
+ {'domain': 'reddit.com', 'path': 'search', 'params': 'q=dart'}
+ ];
+
+String assembleUrlsUsingStringBuffer(entries) {
+ StringBuffer sb = new StringBuffer();
+ for (final item in entries) {
+ sb.write(item['scheme'] != null ? item['scheme'] : 'http');
+ sb.write("://");
+ sb.write(item['domain']);
+ sb.write('/');
+ sb.write(item['path'] != null ? item['path'] : '');
+ if (item['params'] != null) {
+ sb.write('?');
+ sb.write(item['params']);
+ }
+ sb.write('\n');
+ }
+ return sb.toString();
+}
+
+// https://news.ycombinator.com/
+// http://www.google.com/
+// http://reddit.com/search?q=dart</pre>
+</div></div>
+<div class="paragraph"><p>A StringBuffer collects string fragments, but does not generate a new string
+until <span class="monospaced">toString()</span> is called.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_discussion_4">Discussion</h4>
+<div class="paragraph"><p>Using a StringBuffer is vastly more efficient than concatenating fragments
+at each step: Consider this rewrite of the above code:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>String assembleUrlsUsingConcat(entries) {
+ var urls = '';
+ for (final item in entries) {
+ urls = urls.concat(item['scheme'] != null ? item['scheme'] : 'http');
+ urls = urls.concat("://");
+ urls = urls.concat(item['domain']);
+ urls = urls.concat('/');
+ urls = urls.concat(item['path'] != null ? item['path'] : '');
+ if (item['params'] != null) {
+ urls = urls.concat('?');
+ urls = urls.concat(item['params']);
+ }
+ urls = urls.concat('\n');
+ }
+ return urls;
+}</pre>
+</div></div>
+<div class="paragraph"><p>This approach produces the exact same result, but incurs the cost of
+joining strings multiple times.</p></div>
+<div class="paragraph"><p>See the <em>Concatenating Strings</em> recipe for a description of <span class="monospaced">concat()</span>.</p></div>
+<div class="sect4">
+<h5 id="_other_stringbuffer_methods">Other StringBuffer methods</h5>
+<div class="paragraph"><p>In addition to <span class="monospaced">write()</span>, the StringBuffer class provides methods to
+write a list of strings (<span class="monospaced">writeAll()</span>), write a numerical character code
+(<span class="monospaced">writeCharCode()</span>), write with an added newline (<span class="monospaced">writeln()</span>), and
+more. The example below shows how to use these methods:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var sb = new StringBuffer();
+sb.writeln('The Beatles:');
+sb.writeAll(['John, ', 'Paul, ', 'George, and Ringo']);
+sb.writeCharCode(33); // charCode for '!'.
+var beatles = sb.toString(); // 'The Beatles:\nJohn, Paul, George, and Ringo!'</pre>
+</div></div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_determining_whether_a_string_is_empty">Determining whether a string is empty</h3>
+<div class="sect3">
+<h4 id="_problem_5">Problem</h4>
+<div class="paragraph"><p>You want to know whether a string is empty. You tried <span class="monospaced">if (string) {...}</span>, but
+that did not work.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_5">Solution</h4>
+<div class="paragraph"><p>Use <span class="monospaced">string.isEmpty</span>:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var emptyString = '';
+print(emptyString.isEmpty); // true</pre>
+</div></div>
+<div class="paragraph"><p>You can also just use <span class="monospaced">==</span>:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>if (string == '') {...} // True if string is empty.</pre>
+</div></div>
+<div class="paragraph"><p>A string with a space is not empty:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var space = ' ';
+print(space.isEmpty); // false</pre>
+</div></div>
+</div>
+<div class="sect3">
+<h4 id="_discussion_5">Discussion</h4>
+<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
+except the boolean true evaluate to false, so <span class="monospaced">if(string)</span> is always false. You
+will see a warning in the editor if you use an <em>if</em> statement with a non-boolean
+in checked mode.</p></div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_removing_leading_and_trailing_whitespace">Removing leading and trailing whitespace</h3>
+<div class="sect3">
+<h4 id="_problem_6">Problem</h4>
+<div class="paragraph"><p>You want to remove spaces, tabs, and other whitespace from the beginning and
+end of strings.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_6">Solution</h4>
+<div class="paragraph"><p>Use <span class="monospaced">string.trim()</span>:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var space = '\n\r\f\t\v'; // A variety of space characters.
+var string = '$space X $space';
+var newString = string.trim(); // 'X'</pre>
+</div></div>
+<div class="paragraph"><p>The String class has no methods to remove only leading or only trailing
+whitespace. You can always use a RegExp.</p></div>
+<div class="paragraph"><p>Remove only leading whitespace:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var newString = string.replaceFirst(new RegExp(r'^\s+'), ''); // 'X \n\r\f\t\v'</pre>
+</div></div>
+<div class="paragraph"><p>Remove only trailing whitespace:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var newString = string.replaceFirst(new RegExp(r'\s+$'), ''); // '\n\r\f\t\v X'</pre>
+</div></div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_changing_string_case">Changing string case</h3>
+<div class="sect3">
+<h4 id="_problem_7">Problem</h4>
+<div class="paragraph"><p>You want to change the case of strings.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_7">Solution</h4>
+<div class="paragraph"><p>Use String&#8217;s <span class="monospaced">toUpperCase()</span> and <span class="monospaced">toLowerCase()</span> methods:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var theOneILove = 'I love Lucy';
+theOneILove.toUpperCase(); // 'I LOVE LUCY!'
+theOneILove.toLowerCase(); // 'i love lucy!'
+
+// Zeus in modern Greek.
+var zeus = '\u0394\u03af\u03b1\u03c2'; // 'Δίας'
+zeus.toUpperCase(); // 'ΔΊΑΣ'
+
+var resume = '\u0052\u00e9\u0073\u0075\u006d\u00e9'; // 'Résumé'
+resume.toLowerCase(); // 'résumé'</pre>
+</div></div>
+<div class="paragraph"><p>The <span class="monospaced">toUpperCase()</span> and <span class="monospaced">toLowerCase()</span> methods don&#8217;t affect the characters of
+scripts such as Devanagri that don&#8217;t have distinct letter cases.</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var chickenKebab = '\u091a\u093f\u0915\u0928 \u0915\u092c\u093e\u092c';
+// 'चिकन कबाब' (in Devanagari)
+chickenKebab.toLowerCase(); // 'चिकन कबाब'
+chickenKebab.toUpperCase(); // 'चिकन कबाब'</pre>
+</div></div>
+<div class="paragraph"><p>If a character&#8217;s case does not change when using <span class="monospaced">toUpperCase()</span> and
+<span class="monospaced">toLowerCase()</span>, it is most likely because the character only has one
+form.</p></div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_handling_extended_characters_that_are_composed_of_multiple_code_units">Handling extended characters that are composed of multiple code units</h3>
+<div class="sect3">
+<h4 id="_problem_8">Problem</h4>
+<div class="paragraph"><p>You want to use emoticons and other special symbols that don&#8217;t fit into 16
+bits. How can you create such strings and use them correctly in your code?</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_8">Solution</h4>
+<div class="paragraph"><p>You can create an extended character using <span class="monospaced">'\u{}'</span> syntax:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var clef = '\u{1F3BC}'; // 🎼</pre>
+</div></div>
+</div>
+<div class="sect3">
+<h4 id="_discussion_6">Discussion</h4>
+<div class="paragraph"><p>Most UTF-16 strings are stored as two-byte (16 bit) code sequences.
+Since two bytes can only contain the 65,536 characters in the 0x0 to 0xFFFF
+range, a pair of strings is used to store values in the 0x10000 to 0x10FFFF
+range. These strings only have semantic meaning as a pair. Individually, they
+are invalid UTF-16 strings. The term <em>surrogate pair</em> is often used to
+describe these strings.</p></div>
+<div class="paragraph"><p>The clef glyph <span class="monospaced">'\u{1F3BC}'</span> is composed of the <span class="monospaced">'\uD83C'</span> and <span class="monospaced">'\uDFBC'</span>
+surrogate pair.</p></div>
+<div class="paragraph"><p>You can get an extended string&#8217;s surrogate pair through its <span class="monospaced">codeUnits</span>
+property:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>clef.codeUnits.map((codeUnit) =&gt; codeUnit.toRadixString(16));
+// ['d83c', 'dfbc']</pre>
+</div></div>
+<div class="paragraph"><p>Accessing a surrogate pair member leads to errors, and you should avoid
+properties and methods that expose it:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>print('\ud83c'); // Error: '\ud83c' is not a valid string.
+print('\udfbc'); // Error: '\udfbc' is not a valid string either.
+clef.split()[1]; // Error: accessing half of a surrogate pair.
+print(clef[i];) // Again, error: accessing half of a surrogate pair.</pre>
+</div></div>
+<div class="paragraph"><p>When dealing with strings containing extended characters, you should use the
+<span class="monospaced">runes</span> getter.</p></div>
+<div class="paragraph"><p>To get the string&#8217;s length, use <span class="monospaced">string.runes.length</span>. Don&#8217;t use
+<span class="monospaced">string.length</span>:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>print(clef.runes.length); // 1
+print(clef.length); // 2
+print(clef.codeUnits.length); // 2</pre>
+</div></div>
+<div class="paragraph"><p>To get an individual character or its numeric equivalent, index the rune list:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>print(clef.runes.toList()[0]); // 127932 ('\u{1F3BC}')</pre>
+</div></div>
+<div class="paragraph"><p>To get the string&#8217;s characters as a list, map the string runes:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var clef = '\u{1F3BC}'; // 🎼
+var title = '$clef list:'
+print(subject.runes.map((rune) =&gt; new String.fromCharCode(rune)).toList());
+// ['🎼', ' ', 'l', 'i', 's', 't', ':']</pre>
+</div></div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_converting_between_characters_and_numerical_codes">Converting between characters and numerical codes</h3>
+<div class="sect3">
+<h4 id="_problem_9">Problem</h4>
+<div class="paragraph"><p>You want to convert string characters into numerical codes and vice versa.
+You want to do this because sometimes you need to compare characters in a string
+to numerical values coming from another source. Or, maybe you want to split a
+string and then operate on each character.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_9">Solution</h4>
+<div class="paragraph"><p>Use the <span class="monospaced">runes</span> getter to get a string&#8217;s code points:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>'Dart'.runes.toList(); // [68, 97, 114, 116]
+
+var smileyFace = '\u263A'; // ☺
+print(smileyFace.runes.toList()); // [9786], (equivalent to ['\u263A']).
+
+var clef = '\u{1F3BC}'; // 🎼
+print(clef.runes.toList()); // [127932], (equivalent to ['\u{1F3BC}']).</pre>
+</div></div>
+<div class="paragraph"><p>Use <span class="monospaced">string.codeUnits</span> to get a string&#8217;s UTF-16 code units:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>'Dart'.codeUnits.toList(); // [68, 97, 114, 116]
+smileyFace.codeUnits.toList(); // [9786]
+clef.codeUnits.toList(); // [55356, 57276]</pre>
+</div></div>
+<div class="sect4">
+<h5 id="_using_codeunitat_to_get_individual_code_units">Using codeUnitAt() to get individual code units</h5>
+<div class="paragraph"><p>To get the code unit at a particular index, use <span class="monospaced">codeUnitAt()</span>:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>'Dart'.codeUnitAt(0); // 68
+smileyFace.codeUnitAt(0); // 9786 (the decimal value of '\u263A')
+clef.codeUnitAt(0); // 55356 (does not represent a legal string)</pre>
+</div></div>
+</div>
+</div>
+<div class="sect3">
+<h4 id="_converting_numerical_codes_to_strings">Converting numerical codes to strings</h4>
+<div class="paragraph"><p>You can generate a new string from numerical codes using the factory
+<span class="monospaced">String.fromCharCodes(charCodes)</span>. You can pass either runes or code units and
+<span class="monospaced">String.fromCharCodes(charCodes)</span> can tell the difference and do the right
+thing automatically:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>print(new String.fromCharCodes([68, 97, 114, 116])); // 'Dart'
+
+print(new String.fromCharCodes([73, 32, 9825, 32, 76, 117, 99, 121]));
+// 'I ♡ Lucy'
+
+// Passing code units representing the surrogate pair.
+print(new String.fromCharCodes([55356, 57276])); // 🎼
+
+// Passing runes.
+print(new String.fromCharCodes([127932])); // 🎼</pre>
+</div></div>
+<div class="paragraph"><p>You can use the <span class="monospaced">String.fromCharCode()</span> factory to convert a single rune
+or code unit to a string:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>new String.fromCharCode(68); // 'D'
+new String.fromCharCode(9786); // ☺
+new String.fromCharCode(127932); // 🎼</pre>
+</div></div>
+<div class="paragraph"><p>Creating a string with only one half of a surrogate pair is permitted,
+but not recommended.</p></div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_calculating_the_length_of_a_string">Calculating the length of a string</h3>
+<div class="sect3">
+<h4 id="_problem_10">Problem</h4>
+<div class="paragraph"><p>You want to get the length of a string, but are not sure how to calculate the
+length correctly when working with variable length Unicode characters.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_10">Solution</h4>
+<div class="paragraph"><p>Use <span class="monospaced">string.runes.length</span> to get the number of characters in a string.</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>print('I love music'.runes.length); // 12</pre>
+</div></div>
+<div class="paragraph"><p>You can safely use <span class="monospaced">string.runes.length</span> to get the length of strings that
+contain extended characters:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var clef = '\u{1F3BC}'; // 🎼
+var subject = '$clef list:'; //
+var music = 'I $hearts $clef'; // 'I ♡ 🎼 '
+
+clef.runes.length; // 1
+music.runes.length // 5</pre>
+</div></div>
+</div>
+<div class="sect3">
+<h4 id="_discussion_7">Discussion</h4>
+<div class="paragraph"><p>You can directly use a string&#8217;s <span class="monospaced">length</span> property (minus <span class="monospaced">runes</span>). This returns
+the string&#8217;s code unit length. Using <span class="monospaced">string.length</span> produces the same length
+as <span class="monospaced">string.runes.length</span> for most unicode characters.</p></div>
+<div class="paragraph"><p>For extended characters, the code unit length is one more than the rune
+length:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>clef.length; // 2
+
+var music = 'I $hearts $clef'; // 'I ♡ 🎼 '
+music.length; // 6</pre>
+</div></div>
+<div class="paragraph"><p>Unless you specifically need the code unit length of a string, use
+<span class="monospaced">string.runes.length</span>.</p></div>
+<div class="sect4">
+<h5 id="_working_with_combined_characters">Working with combined characters</h5>
+<div class="paragraph"><p>It is tempting to brush aside the complexity involved in dealing with runes and
+code units and base the length of the string on the number of characters it
+appears to have. Anyone can tell that <em>Dart</em> has four characters, and <em>Amelié</em>
+has six, right? Almost. The length of <em>Dart</em> is indeed four, but the length of
+<em>Amelié</em> depends on how that string was constructed:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var name = 'Ameli\u00E9'; // 'Amelié'
+var anotherName = 'Ameli\u0065\u0301'; // 'Amelié'
+print(name.length); // 6
+print(anotherName.length); // 7</pre>
+</div></div>
+<div class="paragraph"><p>Both <span class="monospaced">name</span> and <span class="monospaced">anotherName</span> return strings that look the same, but where
+the <em>é</em> is constructed using a different number of runes. This makes it
+impossible to know the length of these strings by just looking at them.</p></div>
+</div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_processing_a_string_one_character_at_a_time">Processing a string one character at a time</h3>
+<div class="sect3">
+<h4 id="_problem_11">Problem</h4>
+<div class="paragraph"><p>You want to do something with each character in a string.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_11">Solution</h4>
+<div class="paragraph"><p>Map the results of calling <span class="monospaced">string.split('')</span>:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var lang= 'Dart';
+
+// ['*D*', '*a*', '*r*', '*t*']
+print(lang.split('').map((char) =&gt; '*${char}*').toList());
+
+var smileyFace = '\u263A';
+var happy = 'I am $smileyFace';
+print(happy.split('')); // ['I', ' ', 'a', 'm', ' ', '☺']</pre>
+</div></div>
+<div class="paragraph"><p>Or, loop over the characters of a string:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var list = [];
+for(var i = 0; i &lt; lang.length; i++) {
+ list.add('*${lang[i]}*');
+}
+
+print(list); // ['*D*', '*a*', '*r*', '*t*']</pre>
+</div></div>
+<div class="paragraph"><p>Or, map the string runes:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>// ['*D*', '*a*', '*r*', '*t*']
+var charList = "Dart".runes.map((rune) {
+ return '*${new String.fromCharCode(rune)}*').toList();
+});
+
+// [[73, 'I'], [32, ' '], [97, 'a'], [109, 'm'], [32, ' '], [9786, '☺']]
+var runeList = happy.runes.map((rune) {
+ return [rune, new String.fromCharCode(rune)]).toList();
+});</pre>
+</div></div>
+<div class="paragraph"><p>When working with extended characters, you should always map the string runes.
+Don&#8217;t use <span class="monospaced">split('')</span> and avoid indexing an extended string. See the <em>Handling
+extended characters that are composed of multiple code units</em> recipe for
+special considerations when working with extended strings.</p></div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_splitting_a_string_into_substrings">Splitting a string into substrings</h3>
+<div class="sect3">
+<h4 id="_problem_12">Problem</h4>
+<div class="paragraph"><p>You want to split a string into substrings using a delimiter or a pattern.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_12">Solution</h4>
+<div class="paragraph"><p>Use the <span class="monospaced">split()</span> method with a string or a RegExp as an argument.</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var smileyFace = '\u263A';
+var happy = 'I am $smileyFace';
+happy.split(' '); // ['I', 'am', '☺']</pre>
+</div></div>
+<div class="paragraph"><p>Here is an example of using <span class="monospaced">split()</span> with a RegExp:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var nums = '2/7 3 4/5 3~/5';
+var numsRegExp = new RegExp(r'(\s|/|~/)');
+nums.split(numsRegExp); // ['2', '7', '3', '4', '5', '3', '5']</pre>
+</div></div>
+<div class="paragraph"><p>In the code above, the string <span class="monospaced">nums</span> contains various numbers, some of which
+are expressed as fractions or as int-divisions. A RegExp splits the string to
+extract just the numbers.</p></div>
+<div class="paragraph"><p>You can perform operations on the matched and unmatched portions of a string
+when using <span class="monospaced">split()</span> with a RegExp:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var phrase = 'Eats SHOOTS leaves';
+
+var newPhrase = phrase.splitMapJoin((new RegExp(r'SHOOTS')),
+ onMatch: (m) =&gt; '*${m.group(0).toLowerCase()}*',
+ onNonMatch: (n) =&gt; n.toUpperCase());
+
+print(newPhrase); // 'EATS *shoots* LEAVES'</pre>
+</div></div>
+<div class="paragraph"><p>The RegExp matches the middle word (<em>SHOOTS</em>). A pair of callbacks are
+registered to transform the matched and unmatched substrings before the
+substrings are joined together again.</p></div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_determining_whether_a_string_contains_another_string">Determining whether a string contains another string</h3>
+<div class="sect3">
+<h4 id="_problem_13">Problem</h4>
+<div class="paragraph"><p>You want to find out whether a string is the substring of another string.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_13">Solution</h4>
+<div class="paragraph"><p>Use <span class="monospaced">string.contains()</span>:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var fact = 'Dart strings are immutable';
+print(fact.contains('immutable')); // True.</pre>
+</div></div>
+<div class="paragraph"><p>You can use a second argument to specify where in the string to start looking:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>print(fact.contains('Dart', 2)); // False</pre>
+</div></div>
+</div>
+<div class="sect3">
+<h4 id="_discussion_8">Discussion</h4>
+<div class="paragraph"><p>The String class provides a couple of shortcuts for testing whether a
+string is a substring of another:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>print(string.startsWith('Dart')); // True.
+print(string.endsWith('e')); // True.</pre>
+</div></div>
+<div class="paragraph"><p>You can also use <span class="monospaced">string.indexOf()</span>, which returns -1 if the substring
+is not found within a string, and otherwise returns the matching index:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var found = string.indexOf('art') != -1; // True, `art` is found in `Dart`.</pre>
+</div></div>
+<div class="paragraph"><p>You can also use a RegExp and <span class="monospaced">hasMatch()</span>:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var found = new RegExp(r'ar[et]').hasMatch(string);
+// True, 'art' and 'are' match.</pre>
+</div></div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_finding_matches_of_a_regexp_pattern_in_a_string">Finding matches of a RegExp pattern in a string</h3>
+<div class="sect3">
+<h4 id="_problem_14">Problem</h4>
+<div class="paragraph"><p>You want to use RegExp to match a pattern in a string, and want to be
+able to access the matches.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_14">Solution</h4>
+<div class="paragraph"><p>Construct a regular expression using the RegExp class, and find matches
+using the <span class="monospaced">allMatches()</span> method:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var neverEatingThat = 'Not with a fox, not in a box';
+var regExp = new RegExp(r'[fb]ox');
+List matches = regExp.allMatches(neverEatingThat);
+print(matches.map((match) =&gt; match.group(0)).toList()); // ['fox', 'box']</pre>
+</div></div>
+</div>
+<div class="sect3">
+<h4 id="_discussion_9">Discussion</h4>
+<div class="paragraph"><p>You can query the object returned by <span class="monospaced">allMatches()</span> to find out the
+number of matches:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var howManyMatches = matches.length; // 2</pre>
+</div></div>
+<div class="paragraph"><p>To find the first match, use <span class="monospaced">firstMatch()</span>:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var firstMatch = RegExp.firstMatch(neverEatingThat).group(0); // 'fox'</pre>
+</div></div>
+<div class="paragraph"><p>To directly get the matched string, use <span class="monospaced">stringMatch()</span>:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>print(regExp.stringMatch(neverEatingThat)); // 'fox'
+print(regExp.stringMatch('I like bagels and lox')); // null</pre>
+</div></div>
+</div>
+</div>
+<div class="sect2">
+<h3 id="_substituting_strings_based_on_regexp_matches">Substituting strings based on RegExp matches</h3>
+<div class="sect3">
+<h4 id="_problem_15">Problem</h4>
+<div class="paragraph"><p>You want to match substrings within a string and make substitutions
+based on the matches.</p></div>
+</div>
+<div class="sect3">
+<h4 id="_solution_15">Solution</h4>
+<div class="paragraph"><p>Construct a regular expression using the RegExp class and make
+replacements using <span class="monospaced">replaceAll()</span> method:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var resume = 'resume'.replaceAll(new RegExp(r'e'), '\u00E9'); // 'résumé'</pre>
+</div></div>
+<div class="paragraph"><p>If you want to replace just the first match, use <span class="monospaced">replaceFirst()</span>:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>// Replace the first match of one or more zeros with an empty string.
+var smallNum = '0.0001'.replaceFirst(new RegExp(r'0+'), ''); // '.0001'</pre>
+</div></div>
+<div class="paragraph"><p>You can use <span class="monospaced">replaceAllMatched()</span> to register a function that modifies the
+matches:</p></div>
+<div class="listingblock">
+<div class="content monospaced">
+<pre>var heart = '\u2661'; // '♡'
+var string = 'I like Ike but I $heart Lucy';
+var regExp = new RegExp(r'[A-Z]\w+');
+var newString = string.replaceAllMapped(regExp, (match) {
+ return match.group(0).toUpperCase()
+});
+print(newString); // 'I like IKE but I ♡ LUCY'</pre>
+</div></div>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div id="footnotes"><hr></div>
+<div id="footer">
+<div id="footer-text">
+Last updated 2013-03-16 10:56:58 PDT
+</div>
+</div>
+</body>
+</html>
« 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