【Qt之QRegExp、QRegularExpression】详解
最佳答案 问答题库808位专家为你答疑解惑
正则表达式
正则表达式由表达式、量词和断言构成。最简单的表达式是一个字符,例如 x 或 5。表达式还可以是方括号中的一组字符。[ABCD] 将匹配 A、B、C 或 D。我们可以将这个表达式写成 [A-D],匹配英文字母表中的任何大写字母的表达式可以写成 [A-Z]。
量词指定必须匹配表达式的出现次数。x{1,1} 表示匹配一个且仅一个 x。x{1,5} 表示匹配一个包含至少一个 x 但不超过五个 x 的字符序列。
请注意,通常情况下,正则表达式不能用于检查平衡的括号或标签。例如,可以编写一个正则表达式来匹配一个开启的 HTML <b>
标签和它的闭合 </b>
标签,但如果 <b>
标签是嵌套的,同样的正则表达式将匹配错误的开启 <b>
标签和闭合 </b>
标签。对于 <b>bold <b>bolder</b></b>
这个片段,第一个 <b>
会与第一个 </b>
匹配,这是不正确的。然而,可以编写一个正则表达式来正确匹配嵌套的括号或标签,但前提是嵌套层级的数量是固定且已知的。如果嵌套层级的数量不是固定且已知的,那么就不可能编写一个不会出错的正则表达式。
假设我们想要一个正则表达式来匹配范围在 0 到 99 的整数。至少需要一个数字,所以我们从表达式 [0-9]{1,1} 开始,它表示精确匹配一个数字。这个正则表达式匹配范围在 0 到 9 的整数。为了匹配范围在 0 到 99 的整数,将最大匹配次数增加到 2,正则表达式变为 [0-9]{1,2}。这个正则表达式满足了最初的要求,即匹配从 0 到 99 的整数,但它也会匹配出现在字符串中间的整数。如果我们希望匹配到的整数恰好是字符串的整个内容,我们必须使用锚定断言,即 ^(脱字符)和 $(美元符号)。当 ^ 是正则表达式的第一个字符时,表示正则表达式必须从字符串开头开始匹配。当 $ 是正则表达式的最后一个字符时,表示正则表达式必须匹配到字符串的结尾。正则表达式变为 ^[0-9]{1,2}$
。请注意,断言,例如 ^ 和 $,不匹配字符,而是字符串中的位置。
如果你在其他地方看过正则表达式的描述,可能会发现它们与这里展示的不同。这是因为一些字符集和一些量词非常常见,它们被赋予了特殊的符号来表示它们。[0-9]
可以用符号\d
替换。匹配恰好出现一次的量词 {1,1}
可以用表达式本身替代,即x{1,1}
与x
是相同的。所以我们的0
到99
匹配器可以写作 ^\d{1,2}$
。它也可以写作 ^\d\d{0,1}$
,即从字符串的开头开始,匹配一个数字,紧接着是 0
或 1
个数字。在实践中,它会被写作 ^\d\d?$
。?
是量词 {0,1}
的简写,即 0
或1
次出现。? 使
表达式成为可选的。正则表达式 ^\d\d?$
的意思是从字符串的开头开始,匹配一个数字,紧接着是 0
或1
个更多的数字,紧接着是字符串的结尾。
要编写一个正则表达式,匹配单词 'mail'
、'letter'
或 'correspondence'
中的任意一个,但不匹配包含这些单词的单词,如 'email'
、'mailman'
、'mailer'
和 'letterbox'
,从匹配'mail'
的正则表达式开始。完整表示,该正则表达式为 m{1,1}a{1,1}i{1,1}l{1,1}
,但因为字符表达式自动由{1,1}
量词匹配,我们可以简化正则表达式为 mail
,即'm'
后跟'a'
后跟'i'
后跟 'l'
。现在,我们可以使用竖线 |,表示或,包括另外两个单词,因此我们用于匹配这三个单词的正则表达式变成了 mail|letter|correspondence
。匹配 'mail'
、'letter'
或 'correspondence'
。虽然这个正则表达式能够匹配我们要匹配的三个单词之一,但它也会匹配我们不想匹配的单词,例如 'email'
。为了防止正则表达式匹配到不想匹配的单词,我们必须告诉它在单词边界处开始和结束匹配。首先将正则表达式用括号括起来,(mail|letter|correspondence)
。括号将表达式分组在一起,并标识我们希望捕获的正则表达式的一部分。将表达式放在括号中允许我们在更复杂的正则表达式中使用它作为组件。它还允许我们检查实际匹配的是这三个单词中的哪一个。为了强制匹配在单词边界开始和结束,我们将正则表达式放在 \b
单词边界断言中:\b(mail|letter|correspondence)\b
。现在正则表达式的意思是:匹配一个单词边界,紧接着是括号中的正则表达式,再紧接着是一个单词边界。断言 \b
匹配的是正则表达式中的位置,而不是字符。单词边界是任何非单词字符,例如,空格、换行符或字符串的开始或结束。
如果我们想要将和符号(&)
替换为 HTML 实体 &
,用于匹配的正则表达式就简单地是 &
。但是这个正则表达式也会匹配已经转换为 HTML 实体的和符号。我们只想替换还没有紧跟在 amp;
后面的和符号,为此,我们需要负向前瞻断言 (?!__)
。那么正则表达式可以写成 &(?!amp;)
,即匹配一个不紧跟在 amp;
后面的和符号。
如果我们想要统计字符串中'Eric'
和'Eirik'
出现的次数,有两个有效的解决方案:\b(Eric|Eirik)\b
和 \bEi?ri[ck]\b
。单词边界断言'\b'
是必需的,以避免匹配包含这两个名字的单词,例如 'Ericsson'
。请注意,第二个正则表达式比我们想要的要匹配更多的拼写形式:'Eric'
、'Erik'
、'Eiric'
和 'Eirik'
。
字符集
方括号表示匹配方括号中包含的任意字符。上面描述的字符集缩写可以出现在方括号中的字符集中。除了字符集缩写和以下两个例外情况,方括号中的字符没有特殊含义。
使用预定义的字符集缩写比跨平台和语言使用字符范围更具可移植性。例如,[0-9]匹配西方字母中的一个数字,但\d匹配任何字母中的一个数字。
注意:在其他regexp文档中,字符集通常被称为“字符类”。
QRegExp
概述
QRegExp
类提供了使用正则表达式进行模式匹配的功能。正则表达式是用于在文本中匹配子字符串的模式。在许多情况下,这非常有用,例如:
- 验证:正则表达式可以测试子字符串是否满足某些条件,例如是否为整数或不包含空格等。
- 搜索:正则表达式提供了比简单的子字符串匹配更强大的模式匹配能力,例如匹配单词
mail
、letter
或correspondence
中的一个,但不匹配email
、mailman
、mailer
、letterbox
等单词。 - 搜索和替换:正则表达式可以将所有出现的子字符串替换为不同子字符串,例如将所有的
&
替换为&
,除非&
后面已经跟着amp;
。 - 字符串拆分:正则表达式可以用于确定如何将字符串拆分为多个部分,例如将制表符分隔的字符串拆分开。
QRegExp
基于Perl
的正则表达式语言,并完全支持Unicode
。QRegExp
还可以以更简单的通配符模式使用,类似于命令行中的功能。可以使用setPatternSyntax()
函数更改QRegExp
使用的语法规则。特别地,可以将模式语法设置为QRegExp::FixedString
,这意味着要匹配的模式被解释为普通字符串,即不转义特殊字符(例如反斜杠)。
注意
:在Qt 5
中,新的QRegularExpression
类提供了与Perl
兼容的正则表达式实现,并建议使用它来替代QRegExp
。
常用方法
构造函数:
- QRegExp():默认构造函数,创建一个空的QRegExp对象。
- QRegExp(const QString &pattern, Qt::CaseSensitivity cs = Qt::CaseSensitive, PatternSyntax syntax = RegExp):根据给定的模式字符串、大小写敏感性和语法规则创建一个QRegExp对象。
- QRegExp(const QRegExp &rx):复制构造函数,创建一个与给定QRegExp对象相同的QRegExp对象。
析构函数:
- ~QRegExp(),析构函数释放QRegExp对象的内存。
方法:
- QString cap(int nth = 0) const:返回第nth个捕获文本的内容。
- int captureCount() const:返回捕获组的数量。
- QStringList capturedTexts() const:返回所有捕获文本的列表。
- Qt::CaseSensitivity caseSensitivity() const:返回当前的大小写敏感性。
- QString errorString() const:返回错误描述字符串。
- bool exactMatch(const QString &str) const:判断给定字符串是否与当前模式完全匹配。
- int indexIn(const QString &str, int offset = 0, CaretMode caretMode = CaretAtZero) const:返回匹配的起始索引位置,如果未找到匹配则返回-1。
- bool isEmpty() const:判断是否为空模式。
- bool isMinimal() const:判断是否为最小化模式。
- bool isValid() const:判断是否为有效的正则表达式。
- int lastIndexIn(const QString &str, int offset = -1, CaretMode caretMode = CaretAtZero) const:返回最后一次匹配的起始索引位置。
- int matchedLength() const:返回匹配的长度。
- QString pattern() const:返回当前模式的字符串表示。
- PatternSyntax patternSyntax() const:返回当前模式的语法类型。
- int pos(int nth = 0) const:返回第nth个捕获组的当前位置。
- void setCaseSensitivity(Qt::CaseSensitivity cs):设置大小写敏感性。
- void setMinimal(bool minimal):设置是否为最小化模式。
- void setPattern(const QString &pattern):设置正则表达式的模式字符串。
- void setPatternSyntax(PatternSyntax syntax):设置正则表达式的语法类型。
- void swap(QRegExp &other):交换两个QRegExp对象的内容。
- bool operator!=(const QRegExp &rx) const:判断两个QRegExp对象是否不相等。
- QRegExp &operator=(const QRegExp &rx):赋值运算符,将一个QRegExp对象赋值给另一个QRegExp对象。
- QRegExp &operator=(QRegExp &&other):移动赋值运算符,将一个QRegExp对象移动赋值给另一个QRegExp对象。
- bool operator==(const QRegExp &rx) const:判断两个QRegExp对象是否相等。
示例1:字符串匹配
// integers 1 to 9999 :在 1 - 9999 区间QRegExp rx("[1-9]\\d{0,3}");// the validator treats the regexp as "^[1-9]\\d{0,3}$" : [1-9]\\d{0,3} = ^[1-9]\\d{0,3}$QRegExpValidator v(rx, 0);QString s;int pos = 0;s = "0";qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << v.validate(s, pos); // returns Invalids = "12345";qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << v.validate(s, pos); // returns Invalids = "1";qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << v.validate(s, pos); // returns Acceptablerx.setPattern("\\S+"); // one or more non-whitespace characters : 一个或多个非空白字符v.setRegExp(rx);s = "myfile.txt";qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << v.validate(s, pos); // Returns Acceptables = "my file.txt";qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << v.validate(s, pos); // Returns Invalid// A, B or C followed by exactly five digits followed by W, X, Y or Z:A、B或C后面正好跟着五位数字,后面跟着W、X、Y或Zrx.setPattern("[A-C]\\d{5}[W-Z]");v.setRegExp(rx);s = "a12345Z";qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << v.validate(s, pos); // Returns Invalids = "A12345Z";qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << v.validate(s, pos); // Returns Acceptables = "B12";qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << v.validate(s, pos); // Returns Intermediate// match most 'readme' files:匹配更多的 'readme' 文本rx.setPattern("read\\S?me(\.(txt|asc|1st))?");rx.setCaseSensitivity(Qt::CaseInsensitive);v.setRegExp(rx);s = "readme";qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << v.validate(s, pos); // Returns Acceptables = "README.1ST";qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << v.validate(s, pos); // Returns Acceptables = "read me.txt";qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << v.validate(s, pos); // Returns Invalids = "readm";qDebug().noquote() << "[" << __FILE__ << __LINE__ << "]" << v.validate(s, pos); // Returns Intermediate
示例2:限制输入框只可输入数字
QRegExp reg;reg.setPattern("^[0-9]*$");ui->lineEdit->setValidator(new QRegExpValidator(reg));
QRegularExpression
注意
:在Qt 5
中,新的QRegularExpression
类提供了与Perl
兼容的正则表达式实现,并建议使用它来替代QRegExp
。
QRegularExpression
是一个实现了与Perl
兼容的正则表达式的类。它完全支持 Unicode
。
正则表达式由两个部分组成:模式和一组模式选项,这些选项可以改变模式字符串的含义。
您可以通过将字符串传递给QRegularExpression
构造函数来设置模式字符串:
QRegularExpression re("a pattern");
这将把模式字符串设置为指定的模式。您还可以使用 setPattern()
函数在现有的 QRegularExpression
对象上设置模式:
QRegularExpression re;re.setPattern("another pattern");
请注意,由于 C++ 字符串字面量的规则,您必须使用另一个反斜杠来转义模式字符串中的所有反斜杠:
// 匹配两个数字后跟一个空格和一个单词QRegularExpression re("\\d\\d \\w+");// 匹配一个反斜杠QRegularExpression re2("\\\\");
pattern()
函数返回当前设置为 QRegularExpression
对象的模式字符串:
QRegularExpression re("a third pattern");QString pattern = re.pattern(); // pattern == "a third pattern"
二者语法一样,下面只介绍QRegularExpression
用法。
若要进行匹配,只需调用 match()
函数并传递一个字符串进行匹配。我们将这个字符串称为主题字符串
。match()
函数的结果是一个 QRegularExpressionMatch 对象
,可用于检查匹配的结果。例如:
// 匹配两个后跟一个空格和一个单词QRegularExpression re("\\d\\d \\w+");QRegularExpressionMatch match = re.match("abc123 def");bool hasMatch = match.hasMatch(); // true
如果匹成功,隐式捕获组编号为 0 的内容将用于检索整个模式匹配的子字符串(也请参考有关提取已捕获子字符串的部分):
QRegularExpression re("\\d\\d \\w+");QRegularExpressionMatch match = re.match("abc123 def");if (match.hasMatch()) {QString matched = match.captured(0); // matched == "23 def"// ...}
还可以通过将偏移量作为match()
函数的参数,在主题字符串中的任意偏移处开始匹配。在下面的示例中,由于匹配从偏移量 1 开始,因此不会匹配 "12 abc"
:
QRegularExpression re("\\d\\d \\w+");QRegularExpressionMatch match = re.match("12 abc 45 def", 1);if (match.hasMatch()) {QString matched = match.captured(0); // matched == "45 def"// ...}
正常匹配
要执行匹配,您可以简单地调用 match()
函数并传递一个字符串进行匹配。我们将这个字符串称为主题字符串
。match()
函数的结果是一个QRegularExpressionMatch
对象,可以用于检查匹配的结果。例如:
// 匹配两个数字,后跟一个空格和一个单词QRegularExpression re("\\d\\d \\w+");QRegularExpressionMatch match = re.match("abc123 def");bool hasMatch = match.hasMatch // true
如果匹配成功,隐式捕获组编号 0 可用于检索整个模式匹配的子字符串(也请参阅有关提取已捕获子字符串的部分):
QRegularExpression re("\\d\\d \\w+");QRegularExpressionMatch match = re.match("abc123 def");if (matchMatch()) {QString matched match.captured(0); // matched == "23 def"// ...}
还可以通过将偏移量作为 match()
函数的,在主题字符串内部任意偏移处开始匹配。在下面的示例中,由于匹配从偏移量 1 开始,因此不会匹配 "12 abc"
:
QRegularExpression re("\\d\\d \\w+");QRegularExpressionMatch match = re.match("12 abc 45 def", 1);if (match.hasMatch()) {QString matched match.captured(0); // matched == "45 def"// ...}
提取已捕获的子字符串
QRegularExpressionMatch
对象还包含有关模式字符串中捕获组捕获的子字符串的信息。captured()
函数将返回第 n 个捕获组捕获的字符串:
QRegularExpression re("^(\\d\\d)/(\\d\\d)/(\\d\\d\\d\\d)$");QRegularExpressionMatch match = re.match("0812/1985");if (match.hasMatch()) {day = match.captured(1); // day == "08"QString month = match.captured(2); // month == "12"QString year = match.captured3); // year == "1985"// ...}
模式中的捕获组编号从 1 开始,隐式捕获组 0 用于捕获与整个模式匹配的子字符串。
还可以通过使用 capturedStart() 和 capturedEnd() 函数检索每个捕获子字符串在主题字符串中的起始和结束偏移量:
QRegularExpression re("abc(\\d+)def");QRegularExpressionMatch match = re.match("XYZabc123defXYZ");if (match.hasMatch()) {int startOffset = match.capturedStart(1); // startOffset == 6int endOffset = match.capturedEnd(1); // endOffset == 9// ...}
所有这些函数都重载了一个接受 QString 参数的版本,以提取命名的捕获子字符串。例如:
QRegularExpression re("^(?<date>\\d\\d)/(?<month>\\d\\d)/(?<year>\\d\\d\\d\\d)$");QRegularExpressionMatch match = re.match("08/12/1985");if (match.hasMatch()) {QString date = match.captured("date"); // date == "08"QString month = match.captured("month"); // month == "12"QString year = match.captured("year"); // year == 1985}
全局匹配
全局匹配非常有用,可以找到主题字符串中给定正则表达式的所有出现。假设我们想从给定的字符串中提取所有的单词,其中单词是与模式 \w+
匹配的子字符串。
QRegularExpression::globalMatch
返回一个 QRegularExpressionMatchIterator
,它是一个类似于Java
的前向迭代器,可用于遍历结果。例如:
QRegularExpression re("(\\w+)");QRegularExpressionMatchIterator i = re.globalMatch("the quick fox");
由于它是一个类似于Java
的迭代器,QRegularExpressionMatchIterator
将立即指向第一个结果之前。每个结果都作为一个 QRegularExpressionMatch
对象返回。hasNext()
函数将返回true
如果还有至少一个结果,而next()
将返回下一个结果并推进迭代器。继续上一个示例:
QStringList words;while (i.hasNext()) {QRegularExpressionMatch match = i.next();QString word = match.captured(1);words << word;}// words 包含 "the", "quick", "fox"
您还可以使用 peekNext()
在不推进迭代器的情况下获取下一个结果。
可以像使用match()
进行正常匹配一样,向globalMatch()
函数传递起始偏移量和一个或多个匹配选项。
部分匹配
假设我们希望用户输入特定格式的日期,例如“MMM dd,yyyy”
。我们可以使用以下模式来检查输入的有效性:
^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d\d?, \d\d\d\d$
(此模式无法捕捉无效日期,但为了示例的目的,我们将其保留)。
我们希望在用户键入时使用此正则表达式验证输入,以便一旦提交输入,我们就可以报告输入错误(例如,用户键入了错误的键)。为了做到这一点,我们必须区分三种情况:
- 输入不可能匹配正则表达式;
- 输入匹配正则表达式;
- 输入现在不匹配正则表达式,但如果添加更多字符,它将匹配正则表达式。
请注意,这三个案例恰好代表QValidator
的可能状态(参见QValidator::State枚举)。
特别是,在最后一种情况下,我们希望正则表达式引擎报告部分匹配:我们正在将模式与主题字符串进行成功匹配,但由于遇到了主题的结尾而无法继续匹配。请注意,匹配算法应继续并尝试所有可能性,如果找到完整的(非部分)匹配项,则应报告该匹配项并将输入字符串视为完全有效。
这个行为是通过 PartialPreferCompleteMatch
匹配类型实现的。例如:
QString pattern("^(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \\d\\d?, \\d\\dd\\d$");RegularExpression re(pattern);QString input("Jan 21,");QRegularExpressionMatch match = re.match(input, 0, QRegularExpression::PartialPreferCompleteMatch);bool hasMatch = match.hasMatch(); // falsebool hasPartialMatch = match.hasPartialMatch(); // true
如果对主题字符串使用相同的正则表达式导致完全匹配,它将像通常一样报:
QString input("Dec 8, 1985");QRegularExpressionMatch match = re.match(input, 0, QRegularExpression::PartialPreferCompleteMatch);bool hasMatch = match.hasMatch(); // truebool hasPartialMatch = match.hasPartialMatch(); // false
另一个示例使用不同的模式,展了对完全匹配的偏好行为:
QRegularExpression re("abc\\w+X|def");QRegularExpressionMatch match = re.match("abcdef", 0, QRegularExpression::PartialPreferCompleteMatch);bool hasMatch = match.hasMatch(); // truebool hasPartialMatch = match.hasPartialMatch(); // falseQString captured = match.captured(0); // captured == "def"
在这种情况下,子模式 abc\w+X 部分匹配主题字符串;然而,子模式 def 完全匹配主题字符串,因此报告的是完全匹配。
如果在匹配时发现多个部分匹配(但没有完全匹配),则 QRegularExpressionMatch 对象将报告找到的第一个部分匹配。例如:
QRegularExpression re("abc\\w+X|defY");QRegularExpressionMatch match = re.match("abcdef", 0, QRegularExpression::PartialPreferCompleteMatch);bool hasMatch = match.hasMatch(); // falsebool hasPartialMatch = match.hasPartialMatch(); // true QString captured = match.captured(0); // captured == "abcdef"
增量/多段匹配
增量匹配是部分匹配的另一个用例。假设我们想在大文本中找到正则表达式的出现(即与正则表达式匹配的子字符串)。为此,我们希望将大文本以较小的块"喂给"正则表达式引擎。显然的问题是,如果与正则表达式匹配的子字符串跨越两个或更多块,会发生什么情况。
在这种情况下,正则表达式引擎应报告部分匹配,以便我们可以添加新数据再次匹配,并(最终)获得完全匹配。这意味着正则表达式引擎可以假设主题字符串结束后还有其他字符。这不是字面意义上的——引擎永远不会尝试访问主题字符串最后一个字符之后的任何字符。
QRegularExpression
在使用 PartialPreferFirstMatch
匹配类型时实现了这种行为。这种匹配类型在找到部分匹配后立即报告,而不尝试其他匹配替代方案(即使它们可能导致完全匹配)。例如:
QRegularExpression re("abc|ab");QRegularExpressionMatch match = re.match("ab", 0, QRegularExpression::PartialPreferFirstMatch);bool hasMatch = match.hasMatch(); // falsebool hasPartialMatch = match.hasPartialMatch(); // true
这是因为在匹配分支的第一个操作数时找到了部分匹配,因此匹配停止,而不尝试第二个操作数。另一个例子:
QRegularExpression re("abc(def)?");QRegularExpressionMatch match = re.match("abc", 0, QRegularExpression::PartialPreferFirstMatch);bool hasMatch = match.hasMatch(); // falsebool hasPartialMatch = match.hasPartialMatch(); // true
这展示了量词的一种看似反直觉的行为:由于 ?
是贪婪的,引擎首先尝试在匹配"abc"
后继续匹配;但是匹配达到主题字符串的末尾,因此报告了部分匹配。在下面的例子中,这更令人惊讶:
QRegularExpression re("(abc)*");QRegularExpressionMatch match = re.match("abc", 0, QRegularExpression::PartialPreferFirstMatch);bool hasMatch = match.hasMatch(); // falsebool hasPartialMatch = match.hasPartialMatch(); // true
如果我们记得引擎期望主题字符串只是我们要寻找匹配的完整文本的一个子字符串(即之前所说的,引擎假设主题字符串末尾还有其他字符),那么很容易理解这种行为。
由于*
量词是贪婪的,报告完全匹配可能是错误的,因为在当前主题"abc"
后可能还有其他"abc"
的出现。例如,完整的文本可以是"abcabcX"
,因此在完整的文本中报告的正确匹配应该是"abcabc"
;但是仅通过匹配前导的"abc"
,我们得到了一个部分匹配。
99%的人还看了
相似问题
猜你感兴趣
版权申明
本文"【Qt之QRegExp、QRegularExpression】详解":http://eshow365.cn/6-30578-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!