# 2.3.1字符串

> 译文： [https://sicp.comp.nus.edu.sg/chapters/35](https://sicp.comp.nus.edu.sg/chapters/35)

<split>到目前为止，我们已经使用字符串来显示消息，使用了功能`display`和`error`，例如在练习 [1.22](17#ex_1.22)约翰&lt;/quote&gt;的首字母显然是&lt;quote&gt;J。&lt;/quote&gt;如果我们告诉某人&lt;quote&gt;大声说出您的名字，&lt;/quote&gt;我们希望听到该人的名字。 但是，如果我们大声告诉&lt;quote&gt;说&lt;quote&gt;您的名字&lt;/quote&gt;，&lt;/quote&gt;，我们希望听到&lt;quote&gt;您的名字。&lt;/quote&gt; 请注意，我们被迫嵌套引号来描述其他人可能说的话。 [[1]](35#footnote-1)

通过引号，我们可以区分字符串和名称：

```js
const a = 1;
const b = 2;
```

```js
list(a, b);
// [1, [2, null]]
```

```js
list("a", "b");
// ["a", ["b", null]]
```

```js
list("a", b);
// ["a", [2, null]]
```

我们可以使用运算符`===`测试两个字符串是否相同。 [[2]](35#footnote-2) 使用`===`，我们可以实现一个有用的功能，称为`member`。 这需要两个参数，一个字符串和一个列表。 如果该字符串未包含在列表中（即列表中的任何项都不是`===`），则`member`返回false。 否则，它将返回列表的子列表，该列表从字符串的第一次出现开始：

```js
function member(item, x) {
    return is_null(x)
        ? false
        : item === head(x)
          ? x
          : member(item, tail(x));
}
```

For example, the value of

```js
member("apple", list("pear", "banana", "prune"));
```

is false, whereas the value of

```js
member("apple", 
     list("x", list("apple","sauce"), "y", "apple", "pear"));
```

is `["apple", ["pear", null]]`.<exercise>What would the interpreter print in response to evaluating each of the following expressions?

```js
list("a", "b", "c");
```

```js
list(list("george"));
```

```js
tail(list(list("x1", "x2"), list("y1", "y2")));
```

```js
tail(head(list(list("x1", "x2"), list("y1", "y2"))));
```

```js
member("red", list(list("red", "shoes"), list("blue", "socks")));
```

```js
member("red", list("red", "shoes", "blue", "socks"));
```

<button class="btn btn-secondary solution_btn" data-toggle="collapse" href="#solution_35_1_div">Solution</button> <solution>```js
list("a", "b", "c");
// ["a", ["b", ["c", null]]]
```

```js
list(list("george"));
// [["george", null], null]
```

```js
tail(list(list("x1", "x2"), list("y1", "y2")));
// [["y1", ["y2", null]], null]
```

```js
tail(head(list(list("x1", "x2"), list("y1", "y2"))));
// ["x2", null]
```

```js
member("red", list(list("red", "shoes"), list("blue", "socks")));
// false
```

```js
member("red", list("red", "shoes", "blue", "socks"));
// ["red", ["shoes", ["blue", ["socks", null]]]]
```</solution></exercise> <exercise>We would like to define a function `is_equal` that checks whether two lists contain equal elements arranged in the same order. For example,

```js
is_equal(list("this", "is", "a", "list"), 
         list("this", "is", "a", "list"));
```

is true, but

```js
is_equal(list("this", "is", "a", "list"),
         list("this", list("is", "a"), "list"));
```

is false. To be more precise, we can define `is_equal` recursively in terms of the basic `===` equality of strings by saying that `a` and `b` are equal with respect to `is_equal` if they are both strings and the strings are equal with respect to `===`, or if they are both lists such that `head(a)` is equal with respect to `is_equal` to `head(b)` and `tail(a)` is equal with respect to `is_equal` to `tail(b)`. Using this idea, implement `is_equal` as a function.[[3]](35#footnote-3)<button class="btn btn-secondary solution_btn" data-toggle="collapse" href="#solution_35_2_div">Solution</button> <solution>```js
function is_equal(a, b) {
    return (is_pair(a) && is_pair(b) &&
            is_equal(head(a), head(b)) && is_equal(tail(a), tail(b)))
           || 
           a === b;
}
```</solution></exercise> <exercise>The JavaScript interpreter reads the characters after the double quotation mark `"` until it finds another double quotation mark. All characters between the two are part of the string, excluding the double quotation marks, themselves. What if we want a string to contain double quotation marks? For this purpose, JavaScript also allows to use _single_ quotation marks to form strings, as for example in `'say your name aloud'`. Within singly-quoted strings, we can use double quotation marks, and vice versa, so `'say "your name" aloud'` and `"say 'your name' aloud"` are valid strings that have different characters in positions 5 and 15, if we start counting at 1\. Depending on the font in use, two single quotation marks might not be easily distinguishable from a double quotation mark. Can you spot which is which and work out the value of the following expression?

```js
" '' === '' "
```

<button class="btn btn-secondary solution_btn" data-toggle="collapse" href="#solution_35_3_div">Solution</button><solution>The given expression consists of a single string that contains four single quotation marks.</solution></exercise></split>

* * *

[[1]](35#footnote-link-1) Allowing quotation in a language wreaks havoc with the ability to reason about the language in simple terms, because it destroys the notion that equals can be substituted for equals. For example, three is one plus two, but the word <quote>three</quote> is not the phrase <quote>one plus two.</quote> Quotation is powerful because it gives us a way to build expressions that manipulate other expressions (as we will see when we write an interpreter in chapter 4). But allowing statements in a language that talk about other statements in that language makes it very difficult to maintain any coherent principle of what <quote>equals can be substituted for equals</quote> should mean. For example, if we know that the evening star is the morning star, then from the statement <quote>the evening star is Venus</quote> we can deduce <quote>the morning star is Venus.</quote> However, given that <quote>John knows that the evening star is Venus</quote> we cannot infer that <quote>John knows that the morning star is Venus.</quote>

[[2]](35#footnote-link-2) We can consider two strings to be <quote>the same</quote> if they consist of the same characters in the same order. Such a definition skirts a deep issue that we are not yet ready to address: the meaning of <quote>sameness</quote> in a programming language. We will return to this in chapter 3 (section <ref name="sec:costs-of-assignment">[3.1.3](51)</ref>).

[[3]](35#footnote-link-3) In practice, programmers use `is_equal` to compare lists that contain numbers as well as strings. Numbers are not considered to be strings. A better definition of `is_equal` would also stipulate that if `a` and `b` are both numbers, then `a` and `b` are equal with respect to `is_equal` if they are equal with respect to `===`.

