# Alice、Bob 和他们的朋友们

密码学家 Rivest、Shamir、Adleman 于1977年4月撰写了一篇论文《数字签名与公钥密码学》（On Digital Signatures and Public-Key Cryptosystems），并投稿至了一个期刊上，不过很遗憾这篇论文被拒稿了。随后他们修改了论文，并将论文重新命名为《一种实现数字签名和公钥密码系统的方法》（A Method of Obtaining Digital Signatures and Public-Key Cryptosystems），最终于1978年2月成功发表于顶级期刊《ACM通信》（Communications of the ACM）。在这篇论文中，三位密码学家嫌弃使用A、B两个字母代表角色太无聊，就用Alice和Bob来代替A和B。

在随后的几十年里密码学界又新增了很多著名人物。布鲁斯·施奈尔所著的《应用密码学》（Applied Cryptography）里详细列举了这些人物，下面是一些例子：

```python
crypto_roles = [
    '爱丽丝（Alice）是信息发送者。',
    '与鲍伯（Bob）是信息接受者。通例上，爱丽丝希望把一条消息发送给鲍伯。',
    '卡罗尔或查利（Carol或Charlie）是通信中的第三位参加者。',
    '戴夫（Dave）是通信中的第四位参加者。',
    '伊夫（Eve）是一位偷听者（eavesdropper），但行为通常是被动的。她拥有偷听的技术，但不会中途篡改发送的消息。在量子密码学中，伊夫也可以指环境（environment）。'
]
```

Python 是一门多范式编程语言，其中包括面向对象编程。

首先，我们用 `Python 类(class)` 定义一个密码城邦人物类型：

```python
# -*- coding: UTF-8 -*-
class CryptographyPeople:
    def __init__(self, name_cn, name_en, role, desc):
        self.name_cn = name_cn
        self.name_en = name_en
        self.role = role
        self.desc = desc
```

其次，我们添加一个简易的密码城邦人物解析器，它的作用是将类似`'马提尔达（Matilda）是一位商人（merchant），用于电子商务。',`这样的`人物剧本`解析成`CryptographyPeople`，创建一个密码城邦人物：

```python
# -*- coding: UTF-8 -*-
class SimpleCryptographyPeopleParser:
    def __init__(self, text) -> None:
        self.text = text

    def parse(self, desc):
        # 解析名字部分
        name_cn, name_en, rest = self.parse_name(desc)

        # 解析角色部分
        role, rest = self.parse_role(rest)

        # 解析描述不符
        desc = self.parse_desc(rest)

        # 创建密码城邦人物
        people = CryptographyPeople(name_cn, name_en, role, desc)

        return people

    def parse_name(self, text):
        # 解析名字部分
        index = text.find('是')
        name, rest = text[0:index], text[index+1:]

        # 解析中英文名字
        start = name.find('（')
        end = name.find('）')
        name_cn = name[0:start]
        name_en = name[start+1:end]

        return name_cn.strip(), name_en.strip(), rest

    def parse_role(self, text):
        index1 = text.find('。')
        index2 = text.find('，')

        index = 0
        if index1 > 0 and index2 > 0:
            index = min(index1, index2)
        else:
            index = max(index1, index2)

        role, rest = text[0:index], text[index+1:len(text)-1]

        # 去除冗余量词
        counts = ['一名', '一位', '一个']
        for count in counts:
            role = role.replace(count, '')
        return role.strip(), rest.strip()

    def parse_desc(self, name_cn, name_en, role, rest):
        desc = rest
        if desc:
            # 识别自我主语
            self_list = [name_cn, '他', '她']
            for self_item in self_list:
                desc = desc.replace(self_item, '我')
        else:
            # 补充默认描述
            desc = '很高兴认识你'
```

最后，我们希望创建一个密码城邦，它包含 `add` 和 `introduce` 两个方法：

```python
# -*- coding: UTF-8 -*-
class CryptographyCity:
    def __init__(self):
        self.peoples = []

    def add(self, text):
        parser = SimpleCryptographyPeopleParser(text)
        people = parser.parse(text)
        self.peoples.append(people)

    # TODO(YOU): 请在此实现 introduce 方法
```

最终，我们可以构建起密码城邦，并让市民们全部自报家门：

```python
# -*- coding: UTF-8 -*-
if __name__ == '__main__':
    crypto_roles = ...

    city = CryptographyCity()
    for crypto_role in crypto_roles:
        city.add(crypto_role)
    city.introduce()
```

密码城邦人物的自我介绍如下：

```bash
爱丽丝(Alice): 密码学家说我是一位信息发送者，很高兴认识你。
鲍伯(Bob): 密码学家说我是一位信息接受者，通例上，爱丽丝希望把一条消息发送给我。
...
```

请找出以下对类`CryptographyCity`的方法`introduce`的实现中，<span style="color:red">不正确</span>的选项。

## template

```python
class CryptographyPeople:
    def __init__(self, name_cn, name_en, role, desc):
        self.name_cn = name_cn
        self.name_en = name_en
        self.role = role
        self.desc = desc


class SimpleCryptographyPeopleParser:
    def __init__(self, text) -> None:
        self.text = text

    def parse(self, desc):
        # 解析名字部分
        name_cn, name_en, rest = self.parse_name(desc)

        # 解析角色部分
        role, rest = self.parse_role(name_cn, name_en, rest)

        # 解析描述不符
        desc = self.parse_desc(name_cn, name_en, role, rest)

        # 创建密码城邦人物
        people = CryptographyPeople(name_cn, name_en, role, desc)

        return people

    def parse_name(self, text):
        # 解析名字部分
        index = text.find('是')
        name, rest = text[0:index], text[index+1:]

        # 解析中英文名字
        start = name.find('（')
        end = name.find('）')
        name_cn = name[0:start]
        name_en = name[start+1:end]

        return name_cn.strip(), name_en.strip(), rest

    def parse_role(self, name_cn, name_en, text):
        index1 = text.find('。')
        index2 = text.find('，')

        index = 0
        if index1 > 0 and index2 > 0:
            index = min(index1, index2)
        else:
            index = max(index1, index2)

        role, rest = text[0:index], text[index+1:len(text)-1]

        # 去除冗余量词
        counts = ['一名', '一位', '一个']
        for count in counts:
            role = role.replace(count, '')
        return role.strip(), rest.strip()

    def parse_desc(self, name_cn, name_en, role, rest):
        desc = rest
        if desc:
            # 识别自我主语
            self_list = [name_cn, '他', '她']
            for self_item in self_list:
                desc = desc.replace(self_item, '我')
        else:
            # 补充默认描述
            desc = '很高兴认识你'
        return desc


class CryptographyCity:
    def __init__(self):
        self.peoples = []

    def add(self, text):
        parser = SimpleCryptographyPeopleParser(text)
        people = parser.parse(text)
        self.peoples.append(people)

    def introduce(self):
        for people in self.peoples:
            info = f'{people.name_cn}({people.name_en}): 密码学家说我是一位{people.role}，{people.desc}。'
            print(info)


if __name__ == '__main__':
    crypto_roles = [
        '爱丽丝（Alice）是信息发送者。',
        '鲍伯（Bob）是信息接受者。通例上，爱丽丝希望把一条消息发送给鲍伯。',
        '卡罗尔或查利（Carol或Charlie）是通信中的第三位参加者。',
        '戴夫（Dave）是通信中的第四位参加者。',
        '伊夫（Eve）是一位偷听者（eavesdropper），但行为通常是被动的。她拥有偷听的技术，但不会中途篡改发送的消息。在量子密码学中，伊夫也可以指环境（environment）。',
        '艾萨克（Isaac）是互联网服务提供者 (ISP)。',
        '伊凡（Ivan）是发行人，使用于商业密码学中。',
        '贾斯汀（Justin）是司法（justice）机关。',
        '马洛里（Mallory）是一位恶意攻击者（malicious attacker）。与伊夫不同的是，马洛里会篡改发送的消息。对付马洛里所需的信息安全技术比对伊夫的高出很多。有时亦会叫作马文（Marvin）或马利特（Mallet）。',
        '马提尔达（Matilda）是一位商人（merchant），用于电子商务。',
        '奥斯卡（Oscar）是敌人，通常与马洛里一样。',
        '帕特（Pat）或佩吉（Peggy）是证明者（prover），维克托（Victor）是验证者（verifier）。两人会证实一项事件是否有实际进行，多使用于零知识证明。',
        '普特（Plod或Officer Plod）是执法官员。名称来自伊妮·布来敦所著的儿童文学《诺弟》（Noddy）中的角色“普特先生”。',
        '史蒂夫（Steve）是隐写术（Steganography）。',
        '特伦特（Trent）是一位可信赖的仲裁人（trusted arbitrator），中立的第三者，根据存在的协议而判断。',
        '特鲁迪（Trudy）是侵入者（intruder），等同马洛里。',
        '沃特（Walter）是看守人（warden），根据已存在的协议而保护爱丽丝和鲍伯。',
        '佐伊（Zoe）通常是一个安全协议中的最后参与者。'
    ]

    city = CryptographyCity()
    for crypto_role in crypto_roles:
        city.add(crypto_role)
    city.introduce()
```

## 答案

```python
class CryptographyCity:
    def __init__(self):
        self.peoples = []

    def add(self, text):
        parser = SimpleCryptographyPeopleParser(text)
        people = parser.parse(text)
        self.peoples.append(people)

    def introduce():
        for people in peoples:
            say(people)

    def say(people):
        info = f'{people.name_cn}({people.name_en}): 密码学家说我是一位{people.role}，{people.desc}。'
        print(info)
```

## 选项

### for 语句实现

```python
class CryptographyCity:
    def __init__(self):
        self.peoples = []

    def add(self, text):
        parser = SimpleCryptographyPeopleParser(text)
        people = parser.parse(text)
        self.peoples.append(people)

    def introduce(self):
        for people in self.peoples:
            self.say(people)

    def say(self, people):
        info = f'{people.name_cn}({people.name_en}): 密码学家说我是一位{people.role}，{people.desc}。'
        print(info)
```

### while语句实现

```python
class CryptographyCity:
    def __init__(self):
        self.peoples = []

    def add(self, text):
        parser = SimpleCryptographyPeopleParser(text)
        people = parser.parse(text)
        self.peoples.append(people)

    def introduce(self):
        i=0
        while i<len(self.peoples):
            people = self.peoples[i]
            self.say(people)
            i+=1

    def say(self, people):
        info = f'{people.name_cn}({people.name_en}): 密码学家说我是一位{people.role}，{people.desc}。'
        print(info)
```

### 列表表达式

```python
class CryptographyCity:
    def __init__(self):
        self.peoples = []

    def add(self, text):
        parser = SimpleCryptographyPeopleParser(text)
        people = parser.parse(text)
        self.peoples.append(people)

    def introduce(self):
        [self.say(people) for people in self.peoples]

    def say(self, people):
        info = f'{people.name_cn}({people.name_en}): 密码学家说我是一位{people.role}，{people.desc}。'
        print(info)
```
