【 Python 全栈开发 - WEB开发篇 - 40 】正则表达式


一、正则表达式

1.1 什么是正则表达式

正则表达式是一种用于匹配、查找和替换文本的强大工具。它通过定义一个模式,然后在给定的文本中搜索匹配该模式的字符串。在 Python 中,我们可以使用re模块来使用正则表达式。

1.2 正则表达式的作用

正则表达式在文本处理中具有广泛的应用。它可以用于验证输入的格式、提取特定的信息、过滤文本以及替换文本中的特定部分。无论是简单的字符串操作还是复杂的文本处理任务,正则表达式都能提供强大的功能。

1.3 Python 中的正则表达式模块

Python 提供了re模块,它是用于处理正则表达式的标准库。下面是一些常用的re模块函数:

  • re.search(pattern, string): 在给定的字符串中搜索匹配指定模式的第一个位置,并返回一个匹配对象。
  • re.match(pattern, string): 在给定的字符串开头匹配指定模式,并返回一个匹配对象。
  • re.findall(pattern, string): 返回一个列表,其中包含在给定的字符串中所有匹配指定模式的非重叠子字符串。
  • re.sub(pattern, repl, string): 将给定字符串中所有匹配指定模式的部分替换为指定的替换字符串,并返回替换后的字符串。

下面是一些使用正则表达式的 Python 代码示例:

import re

# 使用re.search函数搜索匹配模式的第一个位置
pattern = r'apple'
string = 'I have an apple and a banana'
match = re.search(pattern, string)
if match:
    print('找到匹配位置:', match.start(), '-', match.end())

# 使用re.match函数匹配字符串开头的模式
pattern = r'I have'
match = re.match(pattern, string)
if match:
    print('匹配成功:', match.group())

# 使用re.findall函数返回所有匹配模式的子字符串列表
pattern = r'a\w+'
matches = re.findall(pattern, string)
print('所有匹配的子字符串:', matches)

# 使用re.sub函数替换匹配模式的部分为指定字符串
pattern = r'banana'
replacement = 'orange'
new_string = re.sub(pattern, replacement, string)
print('替换后的字符串:', new_string)

上述代码演示了如何使用正则表达式进行搜索、匹配、查找和替换操作。通过灵活运用正则表达式,我们可以轻松地处理各种文本处理任务。


二、基本语法

2.1 字符匹配

2.1.1 匹配单个字符

在正则表达式中,可以使用普通字符来匹配文本中的对应字符。例如,正则表达式a可以匹配字符串中的字符a

下面是一个简单的示例代码,演示如何使用正则表达式匹配单个字符:

import re

text = "Hello, world!"
pattern = r"o"

result = re.findall(pattern, text)
print(result)  # 输出: ['o', 'o']

在这个例子中,我们使用re.findall()函数来查找匹配正则表达式pattern的字符串。结果会以列表的形式返回,包含了所有匹配的字符。

2.1.2 匹配多个字符

除了匹配单个字符,正则表达式还支持匹配多个字符的模式。可以使用特定的元字符来指定匹配规则。下面列举了几个常用的元字符:

  • .:匹配任意字符(除了换行符)。
  • *:匹配前一个字符零次或多次。
  • +:匹配前一个字符一次或多次。
  • ?:匹配前一个字符零次或一次。
  • {n}:匹配前一个字符恰好出现n次。
  • {n,}:匹配前一个字符至少出现n次。
  • {n,m}:匹配前一个字符出现n到m次。

下面是一个示例代码,展示如何使用元字符来匹配多个字符的模式:

import re

text = "Hello, world!"
pattern = r"o.*l"

result = re.findall(pattern, text)
print(result)  # 输出: ['o, worl']

在这个例子中,正则表达式o.*l表示以字符o开头,后面跟着任意数量的字符,直到字符l结束。因此,它可以匹配到字符串中的o, worl

2.1.3 匹配特殊字符

有些字符在正则表达式中具有特殊的含义,如.*等。如果想要匹配这些特殊字符本身,需要使用转义字符\

下面是一个示例代码,展示如何匹配特殊字符:

import re

text = "www.example.com"
pattern = r"\."

result = re.findall(pattern, text)
print(result)  # 输出: ['.']

在这个例子中,正则表达式\.表示匹配字符.本身。因为.在正则表达式中具有特殊含义,所以需要使用转义字符\来取消它的特殊含义。

2.2 字符类和排除

正则表达式中的字符类用于匹配一组字符中的任意一个字符。字符类使用方括号 [ ] 来定义,并在方括号内列出所需匹配的字符。

2.2.1 匹配字符类

使用字符类可以方便地匹配一个字符是否属于指定的字符集合。例如,[aeiou] 表示匹配任何一个小写元音字母。下面是一个简单的示例代码:

import re

pattern = r'[aeiou]'  # 匹配小写元音字母
text = "Hello, world!"

result = re.findall(pattern, text)
print(result)

输出结果为:

['e', 'o', 'o']

在上述示例中,使用 re.findall() 函数匹配出所有满足模式的字符,并以列表形式返回结果。

2.2.2 排除字符类

排除字符类用于匹配不属于指定字符集合的字符。它使用插入符号 ^ 在方括号内的开头来表示。例如,[^0-9] 表示匹配除了数字之外的任意一个字符。下面是一个示例代码:

import re

pattern = r'[^0-9]'  # 匹配非数字字符
text = "Hello123, world!"

result = re.findall(pattern, text)
print(result)

输出结果为:

['H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd', '!']

在上述示例中,使用 re.findall() 函数匹配出所有不是数字的字符,并以列表形式返回结果。

通过使用字符类和排除字符类,我们可以更加灵活地定义和匹配符合特定条件的字符。这为处理和过滤文本提供了强大的工具。

2.3 重复和数量词

2.3.1 匹配重复字符

有时候我们需要匹配一个字符或一组字符的重复出现。在正则表达式中,我们可以使用特殊字符来表示重复的次数。

使用"+"匹配一个或多个重复字符

当我们希望匹配一个或多个重复字符时,可以使用+符号。例如,正则表达式r"ab+"可以匹配字符串 “a”、“ab”、“abb”、“abbb” 等。

import re

pattern = r"ab+"
strings = ["a", "ab", "abb", "abbb", "ac"]
for string in strings:
    if re.match(pattern, string):
        print(f"匹配成功: {string}")
    else:
        print(f"匹配失败: {string}")

输出结果为:

匹配成功: a
匹配成功: ab
匹配成功: abb
匹配成功: abbb
匹配失败: ac
使用"*"匹配零个或多个重复字符

如果我们希望匹配零个或多个重复字符,可以使用*符号。例如,正则表达式r"ab*"可以匹配字符串 “a”、“ab”、“abb”、“abbb”,甚至是空字符串。

import re

pattern = r"ab*"
strings = ["a", "ab", "abb", "abbb", "ac", ""]
for string in strings:
    if re.match(pattern, string):
        print(f"匹配成功: {string}")
    else:
        print(f"匹配失败: {string}")

输出结果为:

匹配成功: a
匹配成功: ab
匹配成功: abb
匹配成功: abbb
匹配失败: ac
匹配成功: 

2.3.2 匹配指定数量的字符

有时候我们需要匹配特定数量的重复字符。在正则表达式中,我们可以使用花括号表示重复次数。

使用"{n}"匹配恰好 n 次重复字符

当我们希望匹配恰好 n 次重复字符时,可以使用{n}。例如,正则表达式r"a{3}"可以匹配连续出现 3 次的字符 “a”。

import re

pattern = r"a{3}"
strings = ["aa", "aaa", "aaaa", "a", "aaaaa"]
for string in strings:
    if re.match(pattern, string):
        print(f"匹配成功: {string}")
    else:
        print(f"匹配失败: {string}")

输出结果为:

匹配失败: aa
匹配成功: aaa
匹配失败: aaaa
匹配失败: a
匹配失败: aaaaa
使用"{n,}"匹配至少 n 次重复字符

如果我们希望匹配至少 n 次重复字符,可以使用{n,}。例如,正则表达式r"a{2,}"可以匹配至少连续出现 2 次的字符 “a”。

import re

pattern = r"a{2,}"
strings = ["a", "aa", "aaa", "aaaa", "b", "ab", "ba"]
for string in strings:
    if re.match(pattern, string):
        print(f"匹配成功: {string}")
    else:
        print(f"匹配失败: {string}")

输出结果为:

匹配失败: a
匹配成功: aa
匹配成功: aaa
匹配成功: aaaa
匹配失败: b
匹配失败: ab
匹配失败: ba

2.3.3 匹配范围数量的字符

有时候我们希望匹配一定范围内的重复字符。在正则表达式中,我们可以使用{n,m}表示重复次数的范围。

使用"{n,m}"匹配n到m次重复字符

当我们希望匹配 n 到 m 次重复字符时,可以使用{n,m}。例如,正则表达式r"a{2,4}"可以匹配连续出现 2 到 4 次的字符 “a”。

import re

pattern = r"a{2,4}"
strings = ["a", "aa", "aaa", "aaaa", "aaaaa", "b", "ab", "ba"]
for string in strings:
    if re.match(pattern, string):
        print(f"匹配成功: {string}")
    else:
        print(f"匹配失败: {string}")

输出结果为:

匹配失败: a
匹配成功: aa
匹配成功: aaa
匹配成功: aaaa
匹配失败: aaaaa
匹配失败: b
匹配失败: ab
匹配失败: ba

三、特殊字符和转义

正则表达式是一种强大的文本匹配工具,可以通过使用特殊字符和模式来查找、替换和处理字符串。本文将介绍正则表达式中的特殊字符以及如何使用它们进行匹配。

3.1 特殊字符

3.1.1 匹配位置

在正则表达式中,有一些特殊字符可以用来匹配位置而不是具体的字符。以下是几个常用的位置匹配字符:

  • ^:匹配字符串的开头位置。
  • $:匹配字符串的结尾位置。
  • \b:匹配单词的边界位置。
  • \B:匹配非单词的边界位置。

下面是一些代码示例:

import re

# 匹配以"Hello"开头的字符串
pattern1 = r"^Hello"
string1 = "Hello, World!"
match1 = re.search(pattern1, string1)
print(match1)  # 输出: <re.Match object; span=(0, 5), match='Hello'>

# 匹配以"World!"结尾的字符串
pattern2 = r"World!$"
string2 = "Hello, World!"
match2 = re.search(pattern2, string2)
print(match2)  # 输出: <re.Match object; span=(7, 13), match='World!'>

# 匹配包含单词"apple"的字符串
pattern3 = r"\bapple\b"
string3 = "I have an apple."
match3 = re.search(pattern3, string3)
print(match3)  # 输出: <re.Match object; span=(9, 14), match='apple'>

3.1.2 匹配边界

在正则表达式中,可以使用特殊字符来匹配边界。以下是几个常用的匹配边界字符:

  • ^:匹配行的开头。
  • $:匹配行的结尾。
  • \A:匹配字符串的开头。
  • \Z:匹配字符串的结尾。

下面是一些代码示例:

import re

# 匹配以"Hello"开头的行
pattern1 = r"^Hello"
string1 = """Hello, World!
Hello, Python!"""
match1 = re.search(pattern1, string1)
print(match1)  # 输出: <re.Match object; span=(0, 5), match='Hello'>

# 匹配以"Python!"结尾的行
pattern2 = r"Python!$"
string2 = """Hello, World!
Hello, Python!"""
match2 = re.search(pattern2, string2)
print(match2)  # 输出: <re.Match object; span=(14, 21), match='Python!'>

# 匹配以"Hello"开头的字符串
pattern3 = r"\AHello"
string3 = """Hello, World!
Hello, Python!"""
match3 = re.search(pattern3, string3)
print(match3)  # 输出: <re.Match object; span=(0, 5), match='Hello'>

# 匹配以"Python!"结尾的字符串
pattern4 = r"Python!\Z"
string4 = """Hello, World!
Hello, Python!"""
match4 = re.search(pattern4, string4)
print(match4)  # 输出: <re.Match object; span=(14, 21), match='Python!'>

以上是关于特殊字符和转义的介绍,这些特殊字符可以帮助我们更灵活地进行文本匹配和处理。通过合理使用正则表达式,我们可以更高效地处理字符串操作。

3.2 转义字符

在正则表达式中,有一些特殊字符具有特殊的含义,如.*+等。但有时我们需要匹配这些特殊字符本身,而不是它们的特殊含义。这时就需要使用转义字符。

3.2.1 转义字符的使用

转义字符以反斜杠 \ 开始,后面跟着需要转义的字符。当正则表达式中出现转义字符时,它将匹配该字符本身,而不是它的特殊含义。

下面是一个例子,我们想要匹配字符串中的点号 .

import re

text = "Hello. World."
pattern = r"\."
matches = re.findall(pattern, text)
print(matches)  # 输出结果为 ['.']

在上面的代码中,我们使用正则表达式模式 r"\." 来匹配字符串中的点号。由于点号是一个特殊字符,所以我们在前面加上了转义字符 \。运行代码后,我们可以看到输出结果为 ['.'],即成功匹配到了字符串中的点号。

3.2.2 原始字符串和转义字符的区别

在 Python 中,我们可以使用原始字符串(raw string)来表示正则表达式。原始字符串以 r 开头,它会将反斜杠 \ 当作普通字符对待,不进行转义。

下面是一个示例,演示了原始字符串和转义字符的区别:

import re

text = r"\d+"
pattern = r"\d+"
matches = re.findall(text, "1234")
print(matches)  # 输出结果为 ['1234']

matches = re.findall(pattern, "1234")
print(matches)  # 输出结果为 ['1234']

在上面的代码中,我们定义了两个正则表达式模式:textpatterntext 是一个原始字符串,它以 r 开头,所以其中的反斜杠 \ 不进行转义。pattern 是一个普通字符串,其中的反斜杠需要进行转义。

运行代码后,我们可以看到两次匹配的结果都是 ['1234'],说明原始字符串和转义字符的效果是相同的。

总结:

  • 转义字符以反斜杠 \ 开始,用于匹配特殊字符本身。
  • 原始字符串以 r 开头,不对反斜杠进行转义。

通过使用转义字符,我们可以精确地匹配需要的字符,而不受其特殊含义的影响。这在处理一些特殊字符的时候非常有用,帮助我们编写更灵活和准确的正则表达式。


四、分组和捕获

在正则表达式中,分组是一种强大的工具,可以让我们对模式进行更精确的匹配,并且可以在匹配结果中提取特定的部分。

4.1 分组

4.1.1 普通分组

普通分组是最常见的分组方式,使用小括号将要分组的模式括起来。它的作用是将括号内的模式视为一个整体,并对其进行匹配。

例如,我们要匹配一个字符串中连续出现的相同字母,可以使用普通分组来实现:

import re

pattern = r'(\w)\1+'
text = 'Hellooo, Python!!!'

matches = re.findall(pattern, text)
print(matches)  # 输出 ['o', 'o', 'o']

在上述代码中,我们使用了模式 (\w)\1+ 来匹配连续出现的相同字母。其中,(\w) 表示匹配任意一个字母或数字,并将其作为一个分组。\1 表示对第一个分组的引用,即匹配与第一个分组相同的内容。+ 表示匹配一个或多个重复的内容。通过调用 re.findall() 函数,我们可以找到所有匹配的结果,并打印输出。

4.1.2 非捕获分组

非捕获分组是一种特殊的分组,使用 (?:pattern) 的形式进行定义。它的作用是对模式进行分组,但不会保存分组的匹配结果。

下面是一个示例,使用非捕获分组来匹配日期格式的字符串:

import re

pattern = r'\d{4}-(?:\d{2})-(?:\d{2})'
text = 'Today is 2023-07-10'

match = re.search(pattern, text)
if match:
    print(match.group())  # 输出 2023-07-10

在上述代码中,我们使用模式 '\d{4}-(?:\d{2})-(?:\d{2})' 来匹配日期格式的字符串。其中,\d{4} 表示匹配四个数字,即年份的部分;(?:\d{2}) 表示匹配两个数字,即月份和日期的部分。由于使用了非捕获分组 (?:pattern),在调用 match.group() 方法时,不会返回分组的匹配结果,而是返回整个匹配的字符串。

4.2 捕获

正则表达式是一种强大的模式匹配工具,可以用于在字符串中搜索、替换和提取特定的模式。在 Python 中,使用re模块可以进行正则表达式的操作。

4.2.1 命名捕获组

捕获组是正则表达式中用括号括起来的部分,可以用于匹配和提取特定的子字符串。在 Python 的正则表达式中,可以给捕获组起一个有意义的名字,称之为命名捕获组。

下面是一个示例,展示了如何使用命名捕获组:

import re

# 匹配日期格式:YYYY-MM-DD
pattern = r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})"

text = "Today is 2023-07-10."

match = re.search(pattern, text)

if match:
    year = match.group("year")
    month = match.group("month")
    day = match.group("day")
    print(f"Year: {year}, Month: {month}, Day: {day}")

在上面的代码中,正则表达式模式(P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})定义了一个日期的匹配模式。其中,(?P<year>\d{4})表示将匹配的四位数字捕获到名为year的组中,(?P<month>\d{2})表示将匹配的两位数字捕获到名为month的组中,(?P<day>\d{2})表示将匹配的两位数字捕获到名为day的组中。

通过调用match.group("组名")方法,可以提取出对应命名捕获组的内容,并进行打印输出。

4.2.2 引用捕获组

引用捕获组是指在正则表达式中引用已经捕获到的内容。在 Python 中,可以使用\数字的形式引用捕获组。

下面是一个示例,展示了如何使用引用捕获组:

import re

# 匹配连续相同的单词
pattern = r"\b(\w+)\s+\1\b"

text = "Hello Hello World World."

matches = re.findall(pattern, text)

print(matches)  # 输出: ['Hello', 'World']

在上面的代码中,正则表达式模式\b(\w+)\s+\1\b定义了匹配连续相同的单词的模式。其中,\b表示单词边界,(\w+)表示捕获一个或多个字母数字字符的组,\s+表示匹配一个或多个空格字符,\1表示引用第一个捕获组的内容,\b表示单词边界。

通过调用re.findall方法,可以找到所有匹配的连续相同的单词,并将其存储在一个列表中。


五、高级技巧

正则表达式是一种强大的模式匹配工具,但它也有一些高级技巧,可以让我们更灵活地处理字符串。

5.1 贪婪与非贪婪模式

在正则表达式中,默认情况下,量词是贪婪的,即会尽可能多地匹配字符串。但有时我们可能需要使用非贪婪模式,只匹配尽可能少的字符。在量词后面添加一个问号"?",就可以将其转换为非贪婪模式。

例如,假设我们要匹配一个字符串中的所有数字。使用贪婪模式的正则表达式是\d+,它会匹配尽可能多的数字。而使用非贪婪模式的正则表达式是\d+?,它会匹配尽可能少的数字。

下面是一个使用贪婪和非贪婪模式的示例代码:

import re

# 贪婪模式
text = "12345"
pattern = re.compile(r'\d+')
matches = pattern.findall(text)
print("贪婪模式匹配结果:", matches)

# 非贪婪模式
pattern = re.compile(r'\d+?')
matches = pattern.findall(text)
print("非贪婪模式匹配结果:", matches)

输出结果如下:

贪婪模式匹配结果: ['12345']
非贪婪模式匹配结果: ['1', '2', '3', '4', '5']

可以看到,贪婪模式匹配结果是整个字符串,而非贪婪模式匹配结果是单个的数字。

5.2 前向和后向断言

在正则表达式中,前向断言和后向断言是一种零宽度匹配,它们用于在匹配字符串时,要求某个位置前面或后面满足特定的条件。

前向断言使用(?=pattern)的形式,表示要求当前位置后面的字符串匹配pattern

后向断言使用(?<=pattern)的形式,表示要求当前位置前面的字符串匹配pattern

下面是一个使用前向断言和后向断言的示例代码:

import re

# 前向断言
text = "apple123banana"
pattern = re.compile(r'\d+(?=banana)')
matches = pattern.findall(text)
print("前向断言匹配结果:", matches)

# 后向断言
pattern = re.compile(r'(?<=apple)\d+')
matches = pattern.findall(text)
print("后向断言匹配结果:", matches)

输出结果如下:

前向断言匹配结果: ['123']
后向断言匹配结果: ['123']

可以看到,前向断言匹配结果是数字"123",而后向断言匹配结果也是数字"123"。

5.3 替换与替换回调

在正则表达式中,我们可以使用re.sub(pattern, repl, string)函数进行替换操作。其中,pattern是要匹配的正则表达式,repl是用于替换的字符串或替换回调函数,string是要进行替换的原始字符串。

如果repl是字符串,re.sub()函数会将匹配到的部分替换为该字符串。如果repl是替换回调函数,re.sub()函数会将匹配到的部分作为参数传递给回调函数,并使用回调函数的返回值进行替换。

下面是一个使用替换和替换回调的示例代码:

import re

# 替换字符串
text = "Hello, World!"
pattern = re.compile(r'Hello')
replaced = re.sub(pattern, "Hi", text)
print("替换结果:", replaced)

# 替换回调函数
def to_upper(match):
    return match.group(0).upper()

pattern = re.compile(r'\b\w+\b')
replaced = re.sub(pattern, to_upper, text)
print("替换回调结果:", replaced)

输出结果如下:

替换结果: Hi, World!
替换回调结果: HELLO, WORLD!

可以看到,替换结果将"Hello"替换为"Hi",而替换回调结果将字符串中的单词转换为大写。


六、实际应用

6.1 邮箱验证

邮箱验证是一个常见的应用场景,可以通过正则表达式来检查邮箱地址的有效性。以下是一个简单的示例代码:

import re

def validate_email(email):
    pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
    if re.match(pattern, email):
        return True
    else:
        return False

# 测试
print(validate_email('test@example.com'))  # True
print(validate_email('invalid_email'))     # False

在上面的代码中,我们定义了一个validate_email函数来验证邮箱地址。使用re.match函数和正则表达式'^[\w\.-]+@[\w\.-]+\.\w+$'进行匹配。该正则表达式的含义是以字母、数字、下划线、点号或连字符开头,紧接着是@符号,然后是字母、数字、下划线、点号或连字符,最后以字母结尾的字符串。

6.2 URL解析

URL 解析是另一个常见的应用场景,可以使用正则表达式从 URL 中提取出各个部分,例如协议、主机名、路径等。以下是一个简单的示例代码:

import re

def parse_url(url):
    pattern = r'^(?P<protocol>https?)://(?P<host>[\w\.-]+)/(?P<path>.*)$'
    match = re.match(pattern, url)
    if match:
        return match.groupdict()
    else:
        return None

# 测试
url = 'http://www.example.com/path/to/page'
result = parse_url(url)
if result:
    print('协议:', result['protocol'])
    print('主机名:', result['host'])
    print('路径:', result['path'])
else:
    print('URL解析失败')

在上面的代码中,我们定义了一个parse_url函数来解析URL。使用re.match函数和正则表达式'^(?P<protocol>https?)://(?P<host>[\w\.-]+)/(?P<path>.*)$'进行匹配。该正则表达式使用了命名捕获组,通过(?P<name>...)的形式给捕获组命名,从而可以方便地提取出对应的部分。

6.3 日志分析

日志分析是另一个常见的应用场景,可以使用正则表达式从日志文件中提取出特定的信息。以下是一个简单的示例代码:

import re

def analyze_logs(logs):
    pattern = r'^(?P<date>\d{4}-\d{2}-\d{2}) (?P<time>\d{2}:\d{2}:\d{2}) - (?P<message>.*)$'
    matches = re.findall(pattern, logs, re.MULTILINE)
    results = []
    for match in matches:
        result = {
            'date': match[0],
            'time': match[1],
            'message': match[2]
        }
        results.append(result)
    return results

# 测试
logs = '''
2023-07-01 10:30:15 - Error occurred: Invalid input
2023-07-01 11:45:20 - Warning: Low disk space
2023-07-02 09:15:00 - Information: System rebooted
'''

results = analyze_logs(logs)
for result in results:
    print('日期:', result['date'])
    print('时间:', result['time'])
    print('消息:', result['message'])
    print()

在上面的代码中,我们定义了一个analyze_logs函数来分析日志。使用re.findall函数和正则表达式'^(?P<date>\d{4}-\d{2}-\d{2}) (?P<time>\d{2}:\d{2}:\d{2}) - (?P<message>.*)$'进行匹配。该正则表达式用于匹配每行日志的日期、时间和消息。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值