高级写法

格式化字符串

  1. 使用f-strings(格式化字符串字面量): 这是从Python 3.6版本开始提供的最现代、最简洁的字符串格式化方法。你可以在字符串前加上’f’或’F’,并在花括号{}内嵌入表达式。
1
2
3
4
5
name = "Alice"
age = 30
formatted_string = f"我的名字是{name},我今年{age}岁。"
print(formatted_string)
# 输出:"我的名字是Alice,我今年30岁。"
  1. 使用.format()方法: 这种方法允许你使用format()方法的参数替换字符串中的占位符。
1
2
3
4
5
name = "Bob"
age = 25
formatted_string = "我的名字是{},我今年{}岁。".format(name, age)
print(formatted_string)
# 输出:"我的名字是Bob,我今年25岁。"
  1. 使用%运算符(C风格的字符串格式化): 这种方法类似于C语言中的%运算符,是一种较旧的字符串格式化方法。
1
2
3
4
5
name = "Charlie"
age = 35
formatted_string = "我的名字是%s,我今年%d岁。" % (name, age)
print(formatted_string)
# 输出:"我的名字是Charlie,我今年35岁。"
  1. 使用str.format()方法配合位置或命名占位符: 这种方法允许更灵活地控制参数的位置。
1
2
3
4
5
6
7
8
9
10
name = "Eve"
age = 40
formatted_string = "我的名字是{0},我今年{1}岁。".format(name, age)
print(formatted_string)
# 输出:"我的名字是Eve,我今年40岁。"

# 使用命名占位符(Python 3.1+)
formatted_string = "我的名字是{name},我今年{age}岁。".format(name=name, age=age)
print(formatted_string)
# 输出:"我的名字是Eve,我今年40岁。"
  1. 使用str.join()方法: 这种方法用于将序列的元素用给定的字符串连接起来。
1
2
3
4
fruits = ["苹果", "香蕉", "橙子"]
formatted_string = "、".join(fruits)
print(formatted_string)
# 输出:"苹果、香蕉、橙子"

根据你的喜好和Python版本选择合适的方法。一般来说,f-strings由于其可读性和效率而被推荐使用。

匿名函数

匿名函数是一种在Python中定义简单函数的方式,也被称为lambda函数。与普通函数(def定义的函数)不同,匿名函数不需要使用def关键字来定义,而是使用lambda关键字。匿名函数通常用于简单的功能或需要临时使用的小规模函数。

匿名函数的语法如下:

1
lambda arguments: expression
  • lambda:表示创建匿名函数的关键字。
  • arguments:表示函数的参数列表。
  • expression:表示函数的返回值。

使用说明:

  1. 匿名函数通常适用于简单的功能,不建议用于复杂逻辑的函数。
  2. 匿名函数返回一个函数对象,可以将其赋值给一个变量,也可以直接调用它。

实际使用举例: 下面我们将使用匿名函数来实现一些简单的功能。

  1. 计算两个数的和:
1
2
3
add = lambda x, y: x + y
result = add(5, 3)
print(result) # 输出:8
  1. 判断一个数是否为偶数:
1
2
3
is_even = lambda num: num % 2 == 0
print(is_even(10)) # 输出:True
print(is_even(7)) # 输出:False
  1. 对列表进行排序:
1
2
3
fruits = ["apple", "orange", "banana", "grape"]
fruits.sort(key=lambda fruit: len(fruit))
print(fruits) # 输出:['apple', 'grape', 'orange', 'banana']
  1. 使用map()函数对列表元素进行平方运算:
1
2
3
numbers = [1, 2, 3, 4, 5]
squared_numbers = list(map(lambda x: x**2, numbers))
print(squared_numbers) # 输出:[1, 4, 9, 16, 25]
  1. 在函数中使用匿名函数:
1
2
3
4
def apply_operation(func, x, y):
return func(x, y)
result = apply_operation(lambda a, b: a * b, 3, 4)
print(result) # 输出:12

​ 请注意,在使用匿名函数时,要确保它们的功能简单且易于理解。

map方法

map() 是 Python 内置的函数之一,用于将一个函数(或其他可调用对象)应用于一个或多个序列(如列表、元组等)的每个元素,并将结果组成一个新的可迭代对象。它的基本语法如下:

1
map(function, iterable, ...)
  • function: 是一个函数或其他可调用对象,用于处理每个输入元素。
  • iterable: 是一个或多个序列,可以是列表、元组、集合等。

map() 将会返回一个 map 对象,你可以将其转换成列表或其他类型的可迭代对象,如需要的话。

使用说明:

  1. map() 接受一个或多个序列,它们的长度应该相同。如果传入多个序列,那么 function 将接受相同位置上的元素作为参数,这些元素组成一个元组传递给 function
  2. map() 不会修改原始的输入序列,而是返回一个新的可迭代对象,其中包含了 function 处理后的结果。

实际使用举例: 下面我们通过几个例子来说明 map() 的用法。

  1. 将列表中的每个元素求平方:
1
2
3
numbers = [1, 2, 3, 4, 5]
squared_numbers = map(lambda x: x**2, numbers)
print(list(squared_numbers)) # 输出:[1, 4, 9, 16, 25]
  1. 将两个列表对应位置的元素相加:
1
2
3
4
list1 = [1, 2, 3]
list2 = [10, 20, 30]
sum_result = map(lambda x, y: x + y, list1, list2)
print(list(sum_result)) # 输出:[11, 22, 33]
  1. 将字符串列表中的单词变为大写:
1
2
3
words = ["hello", "world", "python"]
upper_words = map(str.upper, words)
print(list(upper_words)) # 输出:['HELLO', 'WORLD', 'PYTHON']
  1. 使用 map() 转换多个序列:
1
2
3
4
numbers = [1, 2, 3, 4, 5]
squares = [1, 4, 9, 16, 25]
addition = map(lambda x, y: x + y, numbers, squares)
print(list(addition)) # 输出:[2, 6, 12, 20, 30]
  1. 使用 map() 转换多个序列并取平均值:
1
2
3
4
5
6
scores1 = [85, 90, 78]
scores2 = [92, 88, 95]
scores3 = [80, 85, 88]

average = map(lambda x, y, z: (x + y + z) / 3, scores1, scores2, scores3)
print(list(average)) # 输出:[85.66666666666667, 87.66666666666667, 87.0]

总结:map() 是一个很有用的函数,可以简化对序列元素的处理,并且能够在一行代码中完成一些常见的数据转换操作。

reduce方法

reduce() 是 Python 中 functools 模块提供的函数,用于对一个序列(如列表或元组)中的元素逐个进行合并处理,最终返回一个结果。它的基本语法如下:

1
functools.reduce(function, iterable[, initializer])
  • function: 是一个二元函数,接受两个参数,并返回一个结果。
  • iterable: 是一个序列,可以是列表、元组、集合等。
  • initializer(可选): 是初始值,如果提供了 initializer,则会在处理序列元素之前将其作为初始值传递给 function

reduce() 在 Python 2 中是内置函数,但在 Python 3 中已经移至 functools 模块。所以在 Python 3 中使用 reduce() 需要先导入 functools 模块。

使用说明:

  1. reduce() 首先将序列中的前两个元素传递给 function,得到一个结果。
  2. 然后将上一步的结果和序列中的下一个元素传递给 function,再得到一个结果。
  3. 依次类推,将每个元素和上一步的结果传递给 function,直到处理完所有元素,得到最终结果。

实际使用举例: 下面我们通过几个例子来说明 reduce() 的用法。

  1. 计算列表中所有元素的累积乘积:
1
2
3
4
from functools import reduce
numbers = [1, 2, 3, 4, 5]
product = reduce(lambda x, y: x * y, numbers)
print(product) # 输出:120
  1. 使用初始值计算列表中所有元素的累积和:
1
2
3
4
5
from functools import reduce
numbers = [1, 2, 3, 4, 5]
initial_value = 10
sum_result = reduce(lambda x, y: x + y, numbers, initial_value)
print(sum_result) # 输出:25
  1. 将字符串列表中的单词拼接成一个句子:
1
2
3
4
from functools import reduce
words = ["Hello", "World", "Python"]
sentence = reduce(lambda x, y: x + " " + y, words)
print(sentence) # 输出:"Hello World Python"
  1. 使用 reduce() 找到列表中的最大值:
1
2
3
4
from functools import reduce
numbers = [15, 32, 8, 20, 45]
max_value = reduce(lambda x, y: x if x > y else y, numbers)
print(max_value) # 输出:45
  1. 使用初始值计算列表中所有元素的平均值:
1
2
3
4
5
from functools import reduce
scores = [85, 90, 78, 92, 88]
initial_value = 0
average = reduce(lambda x, y: x + y, scores, initial_value) / len(scores)
print(average) # 输出:86.6

总结:reduce() 是一个强大的函数,可以用于处理多个元素之间的累积运算,但在 Python 3 中需要导入 functools 模块才能使用。在实际使用中,要确保传递给 reduce() 的函数符合合并运算的要求。

注意二者区别

  • map()reduce() 是 Python 中两个用于处理序列的内置函数,它们都在 functools 模块中提供。

主要区别如下:

  1. 功能不同:
    • map():用于对序列中的每个元素应用一个函数,并返回处理后的结果组成的可迭代对象。
    • reduce():用于对序列中的元素逐个进行合并处理,并返回一个最终结果。
  2. 函数参数不同:
    • map() 接受一个函数和一个或多个序列(可迭代对象)作为参数,将函数应用于序列的每个元素,并返回结果组成的可迭代对象。
    • reduce() 接受一个二元函数和一个序列(可迭代对象)作为参数,该二元函数处理序列中的两个元素,并返回一个结果,然后将该结果与下一个元素继续进行处理,直到处理完所有元素并得到最终结果。
  3. 返回值不同:
    • map() 返回一个 map 对象,你可以将其转换成列表或其他类型的可迭代对象。
    • reduce() 返回一个最终的结果,而不是一个可迭代对象。
  4. 功能使用场景不同:
    • map() 适用于对序列中的每个元素进行相同的操作,例如对列表中的每个元素进行平方、转换为大写等。
    • reduce() 适用于对序列中的元素进行合并运算,例如求和、求积、找到最大值等。

综上所述,map() 用于对序列中的元素逐个进行相同的处理,而 reduce() 用于对序列中的元素进行累积合并操作。它们在不同的场景下有不同的应用。

例子:assic二进制转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from functools import reduce
from operator import add
b = b'123'
for i in b:
print(i)
print(bin(i)[2:].zfill(8))
print(list(map(int, bin(i)[2:].zfill(8))))
print(reduce(add, [list(map(int, bin(i)[2:].zfill(8))) for i in b]))
'''
# 对应输出
49 # ascii 1
00110001 # 1的二进制
[0, 0, 1, 1, 0, 0, 0, 1] # 1的二进制的list
50 # ascii 2
00110010 # 2的二进制
[0, 0, 1, 1, 0, 0, 1, 0] # 2的二进制的list
51
00110011
[0, 0, 1, 1, 0, 0, 1, 1]
# 二进制的list相加
[0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1]
'''

字符串切片

当涉及到字符串切片,有很多有趣且实用的用法。以下是一些示例,展示了字符串切片的不同写法和妙用:

  1. 颠倒字符串
1
2
3
4
s = "Hello, World!"
reversed_string = s[::-1]
print(reversed_string)
# 输出: "!dlroW ,olleH"
  1. 每隔一个字符获取一个子串
1
2
3
4
s = "Hello, World!"
every_other_char = s[::2]
print(every_other_char)
# 输出: "Hlo ol!"
  1. 获取从索引2到索引7之间的子串
1
2
3
s = "Hello, World!"
substring = s[2:8]
print(substring) # 输出: "llo, W"
  1. 获取从索引3开始,直到字符串结束的子串
1
2
3
s = "Hello, World!"
substring = s[3:]
print(substring) # 输出: "lo, World!"
  1. 获取从字符串开始直到索引7之前的子串
1
2
3
s = "Hello, World!"
substring = s[:7]
print(substring) # 输出: "Hello, "
  1. 通过负数索引来获取子串
1
2
3
s = "Hello, World!"
substring = s[-6:-1]
print(substring) # 输出: "World"
  1. 获取最后3个字符的子串
1
2
3
es = "Hello, World!"
last_three_chars = s[-3:]
print(last_three_chars) # 输出: "ld!"
  1. 复制整个字符串
1
2
3
s = "Hello, World!"
copied_string = s[:]
print(copied_string) # 输出: "Hello, World!"

字符串常用前缀解释

在Python中,使用不同的前缀可以改变字符串的解释方式。

  1. b 前缀(字节字符串): 使用b前缀创建字节字符串,它表示以字节为单位的字符串,不会进行Unicode编码,适用于处理二进制数据。

    1
    binary_data = b"Hello, world!"  # 创建字节字符串
  2. r 前缀(原始字符串): 使用r前缀创建原始字符串,该字符串中的转义字符(如\n)不会被转义,适用于正则表达式、文件路径等。

    1
    2
    regex_pattern = r"\d{3}-\d{2}-\d{4}"  # 创建原始字符串,用于正则表达式
    file_path = r"C:\Users\username\file.txt" # 创建原始字符串,用于文件路径
  3. u 前缀(Unicode字符串): 在Python 2.x 中,使用u前缀创建Unicode字符串,表示字符串是以Unicode编码的。在Python 3中,字符串默认为Unicode,因此不再需要显式使用u前缀。

    1
    unicode_string = u"こんにちは"  # 在Python 2中使用u前缀创建Unicode字符串
  4. f 前缀(格式化字符串): 使用f前缀创建格式化字符串,可以在字符串中插入变量或表达式,并使用花括号 {} 来界定。

    1
    2
    3
    name = "Alice"
    age = 30
    formatted_string = f"My name is {name} and I am {age} years old." # 创建格式化字符串

Python正则表达式操作指南:re库的使用

基本函数介绍与示例

re.search(pattern, string) 搜索匹配模式的第一个位置

这个函数会在给定字符串中搜索匹配给定模式的第一个出现位置。如果找到匹配,它会返回一个匹配对象;如果没有找到,返回None

1
2
3
4
5
6
7
pattern = r'\d{3}-\d{2}-\d{4}'
text = "Date of birth: 01-15-1990"
match = re.search(pattern, text)
if match:
print("Date found:", match.group())
else:
print("Date not found")

在这个示例中,我们使用了\d{3}-\d{2}-\d{4}的模式,它会匹配类似日期格式的字符串。search函数找到匹配后,我们通过match.group()获取匹配的字符串。

re.match(pattern, string) 从字符串开头匹配模式

这个函数会从字符串开头开始尝试匹配给定模式。如果在开头找到匹配,返回一个匹配对象;否则返回None

1
2
3
4
5
6
7
pattern = r'Hello'
text = "Hello, world!"
match = re.match(pattern, text)
if match:
print("Matched:", match.group())
else:
print("No match")

在这个示例中,我们使用了Hello的模式,然后用match函数尝试在开头匹配这个模式。在这种情况下,字符串开头的确匹配了模式。

re.findall(pattern, string) 查找所有匹配模式的子字符串

这个函数会查找并返回所有在字符串中匹配给定模式的子字符串。

1
2
3
4
pattern = r'\d+'
text = "There are 123 apples and 456 oranges."
numbers = re.findall(pattern, text)
print("Numbers:", numbers)

在这个示例中,我们使用了\d+的模式,它会匹配连续的数字。findall函数会返回所有匹配的数字子字符串。

re.finditer(pattern, string) 返回匹配模式的迭代器

这个函数返回一个迭代器,可以通过遍历获取所有在字符串中匹配给定模式的匹配对象。

1
2
3
4
5
pattern = r'\b\w+\b'
text = "Hello world, how are you?"
matches = re.finditer(pattern, text)
for match in matches:
print("Word:", match.group())

在这个示例中,我们使用了\b\w+\b的模式,它会匹配单词边界并提取单词。finditer函数返回一个迭代器,通过遍历迭代器,我们可以获取每个匹配的单词。

re.sub(pattern, replacement, string) - 替换匹配模式的字符串

这个函数会在字符串中查找匹配给定模式的子字符串,并将其替换为指定的字符串。

1
2
3
4
pattern = r'apple'
text = "I like apples, do you like apples?"
new_text = re.sub(pattern, "orange", text)
print("New text:", new_text)

在这个示例中,我们使用了apple的模式,然后用sub函数将所有的apple替换为orange。这样,我们得到了一个新的字符串。

re.split(pattern, string) - 使用匹配模式分割字符串

这个函数会使用匹配给定模式的子字符串来分割字符串,返回分割后的部分列表。

1
2
3
4
pattern = r'[,.]'
text = "Hello, world. How are you?"
parts = re.split(pattern, text)
print("Parts:", parts)

在这个示例中,我们使用了[,.]的模式,它会匹配逗号和句号。split函数会使用这个模式来分割字符串,返回一个包含各个部分的列表。

提高效率的技巧

  1. 使用编译的正则表达式对象: 如果你在代码中多次使用同一模式,使用re.compile()函数创建一个编译过的正则表达式对象,以提高匹配效率。
1
2
3
pattern = re.compile(r'\d{3}-\d{2}-\d{4}')
text = "Dates: 01-01-2023 and 12-31-2023"
dates = pattern.findall(text)

在这个示例中,我们首先使用re.compile()编译了一个正则表达式对象,然后在不同的地方多次使用它来查找日期。

  1. 使用非贪婪模式: 非贪婪模式可以避免匹配时间过长。在量词后面加上?可以实现非贪婪匹配。
1
2
3
4
pattern = r'<.*?>'  # 贪婪匹配
pattern = r'<.*>' # 非贪婪匹配
text = "<p>first</p><p>second</p>"
matches = re.findall(pattern, text)

在这个示例中,我们演示了贪婪匹配和非贪婪匹配的区别。贪婪匹配会尽可能多地匹配字符,而非贪婪匹配只会匹配到第一个匹配。

  1. 使用字符集缩小匹配范围: 在字符集中使用只包含可能的字符,而不是使用点号(.),可以提高匹配速度。
1
2
3
pattern = r'[aeiou]'  # 匹配元音字母
text = "Hello, how are you?"
vowels = re.findall(pattern, text)

在这个示例中,我们使用了字符集[aeiou]来匹配元音字母。这比使用点号来匹配任意字符更有效率。

注意事项与常见错误

  1. 转义字符: 正则表达式中的一些字符具有特殊意义,需要使用反斜杠进行转义,如\d表示数字。如果你要匹配反斜杠本身,需要使用\\
  2. 原始字符串: 在正则表达式中,建议使用原始字符串(使用r前缀),以避免处理转义字符带来的麻烦。
  3. 量词和分组: 学习如何使用量词(*+?{}等)和分组来构建复杂的模式。
  4. 性能考虑: 正则表达式可能导致性能问题,特别是在处理大量数据时。要使用优化的模式和技巧来提高效率。

第三方库使用

pwntools

send&recv:数据交互方式汇总

pwntools 库中,有几个常用的数据交互方法,包括 sendsendlinesendaftersendlineafterrecvuntilrecv,它们在与远程服务通信时都有不同的特性和用途。

  1. send(date)
    • 特性:发送指定的数据 data 给远程服务器,但不自动添加换行符。
    • 区别:与 sendline 相比,不会自动添加换行符,需要手动处理数据格式。
    • 使用情景:适用于发送不需要换行符结尾的数据,比如二进制数据或不需要自动回车的命令。
    • 示例:
1
2
3
4
# 创建与远程服务的连接
r = remote('example.com', 1337)
# 发送数据,无需换行符
r.send("Hello, world!")
  1. sendline(data)
  • 特性:发送指定的数据 data 给远程服务器,并自动添加换行符 (newline)。
  • 区别:相比 send,更方便发送带有换行符结尾的数据。
  • 使用情景:适用于发送需要自动回车的命令,比如交互式命令行操作。
  • 示例:
1
2
3
4
# 创建与远程服务的连接
r = remote('example.com', 1337)
# 发送带有换行符的数据
r.sendline("login admin")
  1. sendafter(sub, data)
  • 特性:等待字符串 sub 在输出中出现,然后发送指定的数据 data 给远程服务器。
  • 区别:用于在交互时根据之前输出的内容,自动判断何时发送数据。
  • 使用情景:适用于根据程序输出的特定字符串来动态发送数据,典型用法是在登录过程中根据提示输入用户名和密码。
  • 示例:
1
2
3
4
5
6
7
8
# 创建与远程服务的连接
r = remote('example.com', 1337)

# 等待字符串 "Username: " 在输出中出现,然后发送用户名
r.sendafter("Username: ", "john_doe")

# 等待字符串 "Password: " 在输出中出现,然后发送密码
r.sendafter("Password: ", "secretpass")
  1. sendlineafter(sub, data)
  • 特性:等待字符串 sub 在输出中出现,然后发送指定的数据 data 给远程服务器,并自动添加换行符 (newline)。
  • 区别:结合了 sendlinesendafter 的功能。
  • 使用情景:适用于根据程序输出的特定字符串来动态发送需要自动回车的数据。
  • 示例:
1
2
3
4
5
6
7
8
# 创建与远程服务的连接
r = remote('example.com', 1337)

# 等待字符串 "Enter your name: " 在输出中出现,然后发送带有换行符的名字
r.sendlineafter("Enter your name: ", "Alice")

# 等待字符串 "Enter your age: " 在输出中出现,然后发送带有换行符的年龄
r.sendlineafter("Enter your age: ", "25")
  1. recvuntil(delims)
  • 特性:接收远程服务器的输出,直到遇到指定的分隔符 delims
  • 区别:与 recv 相比,可以等待特定字符串之前的输出。
  • 使用情景:适用于在得到某些输出之前,等待服务器输出的其他内容。
  • 示例:
1
2
3
4
5
6
7
8
# 创建与远程服务的连接
r = remote('example.com', 1337)

# 接收输出,直到遇到 "Username: " 字符串
output = r.recvuntil("Username: ")

# 输出接收到的内容
print(output)
  1. recv(n)
  • 特性:接收指定字节数 n 的数据。
  • 区别:与 recvuntil 相比,直接接收指定字节数的数据,不需要等待特定分隔符。
  • 使用情景:适用于直接接收固定长度的数据。
  • 示例:
1
2
3
4
5
6
7
8
# 创建与远程服务的连接
r = remote('example.com', 1337)

# 接收固定长度的数据
data = r.recv(1024)

# 处理接收到的数据
print(data)

gdb查看内存命令

/s 查看相应地址的字符串
x/i 查看汇编指令
x/gx 查看相应地址的二进制信息
x/wx 按照字节形式显示二进制信息