# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python [py35]
#     language: python
#     name: Python [py35]
# ---

# # 7.3 String Manipulation（字符串处理）
#
# python很多内建方法很适合处理string。而且对于更复杂的模式，可以配合使用正则表达式。而pandas则混合了两种方式。
#
# # 1 String Object Methods（字符串对象方法）
#
# 大部分string处理，使用内建的一些方法就足够了。比如，可以用split来分割用逗号区分的字符串：

val = 'a,b, guido'

val.split(',')

# split经常和strip一起搭配使用来去除空格（包括换行符）:

pieces = [x.strip() for x in val.split(',')]
pieces

# 可以使用+号把::和字符串连起来：

first, second, third = pieces

first + '::' + second + '::' + third

# 但这种方法并不python，更快的方法是直接用join方法：

'::'.join(pieces)

# 其他一些方法适合锁定子字符串位置相关的。用in关键字是检测substring最好的方法，当然，index和find也能完成任务：

'guido' in val

val.index(',')

val.find(':')

# 注意index和find的区别。如果要找的string不存在的话，index会报错。而find会返回-1:

val.index(':')

# count会返回一个substring出现的次数：

val.count(',')

# replace会取代一种出现方式（pattern）。也通常用于删除pattern，传入一个空字符串即可：

val.replace(',', '::')

val.replace(',', '')

# 这里一些内建的string方法：
#
# ![](http://oydgk2hgw.bkt.clouddn.com/pydata-book/m643y.png)
#
# # 2 Regular Expressions（正则表达式）
#
# 正则表达式能让我们寻找更复杂的pattern。通常称一个表达式为regex，由正则表达语言来代表一个字符串模式。可以使用python内建的re模块来使用。
#
# > 关于正则表达式，有很多教学资源，可以自己找几篇来学一些，这里不会介绍太多。
#
# re模块有以下三个类别：patther matching（模式匹配）, substitution（替换）, splitting（分割）。通常这三种都是相关的，一个regex用来描述一种pattern，这样会有很多种用法。这里举个例子，假设我们想要根据空格（tabs，spaces，newlines）来分割一个字符串。用于描述一个或多个空格的regex是`\s+`:

import re

text = "foo    bar\t baz  \tqux"

re.split('\s+', text)

# 当调用`re.split('\s+', text)`的时候，正则表达式第一次被compile编译，并且split方法会被调用搜索text。我们可以自己编译regex，用re.compile，可以生成一个可以多次使用的regex object：

regex = re.compile('\s+')

regex.split(text)

# 如果想要得到符合regex的所有结果，以一个list结果返回，可以使用findall方法：

regex.findall(text)

# > 为了防止\在正则表达式中的逃逸，推荐使用raw string literal，比如`r'C:\x'`，而不是使用`'C:\\x`
#
# 使用re.compile创建一个regex object是被强烈推荐的，如果你打算把一个表达式用于很多string上的话，这样可以节省CPU的资源。
#
# match和search，与findall关系紧密。不过findall会返回所有匹配的结果，而search只会返回第一次匹配的结果。更严格地说，match只匹配string开始的部分。这里举个例子说明，我们想要找到所有的邮件地址：

# +
text = """Dave <EMAIL> 
          Steve <EMAIL> 
          Rob <EMAIL> 
          Ryan <EMAIL> """

pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'
# -

# re.IGNORECASE makes the regex case-insensitive 
regex = re.compile(pattern, flags=re.IGNORECASE)

# 使用findall找到一组邮件地址：

regex.findall(text)

# search返回text中的第一个匹配结果。match object能告诉我们找到的结果在text中开始和结束的位置：

m = regex.search(text)

m

text[m.start():m.end()]

# regex.match返回None，因为它只会在pattern存在于stirng开头的情况下才会返回匹配结果：

print(regex.match(text))

# 而sub返回一个新的string，把pattern出现的地方替换为我们指定的string：

print(regex.sub('REDACTED', text))

# 假设你想要找到邮件地址，同时，想要把邮件地址分为三个部分，username, domain name, and domain suffix.（用户名，域名，域名后缀）。需要给每一个pattern加一个括号：

pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'

regex = re.compile(pattern, flags=re.IGNORECASE)

# match object会返回一个tuple，包含多个pattern组份，通过groups方法：

m = regex.match('<EMAIL>')

m.groups()

# findall会返回a list of tuples:

regex.findall(text)

# sub也能访问groups的结果，不过要使用特殊符号 \1, \2。\1表示第一个匹配的group，\2表示第二个匹配的group，以此类推：

print(regex.sub(r'Username: \1, Domain: \2, Suffix: \3', text))

# 这里给一些正则表达式的方法：
#
# ![](http://oydgk2hgw.bkt.clouddn.com/pydata-book/mj4vc.png)
#
# # 3 Vectorized String Functions in pandas（pandas中的字符串向量化函数）
#
# 一些复杂的数据清理中，string会有缺失值：

import numpy as np
import pandas as pd

data = {'Dave': '<EMAIL>', 'Steve': '<EMAIL>', 
        'Rob': '<EMAIL>', 'Wes': np.nan}

data = pd.Series(data)
data

data.isnull()

# 可以把一些字符串方法和正则表达式（用lambda或其他函数）用于每一个value上，通过data.map，但是这样会得到NA(null)值。为了解决这个问题，series有一些数组导向的方法可以用于字符串操作，来跳过NA值。这些方法可以通过series的str属性；比如，我们想检查每个电子邮箱地址是否有'gmail' with str.contains:

data.str

data.str.contains('gmail')

# 正则表达式也可以用，配合任意的re选项，比如IGNORECASE：

pattern

data.str.findall(pattern, flags=re.IGNORECASE)

# 有很多方法用于向量化。比如str.get或index索引到str属性：

matches = data.str.match(pattern, flags=re.IGNORECASE)
matches

# 为了访问嵌套list里的元素，我们可以传入一个index给函数：

matches.str.get(1)

matches.str.get(0)

# 也可以使用这个语法进行切片：

data.str[:5]

# 这里有一些字符串向量化的方法：
#
# ![](http://oydgk2hgw.bkt.clouddn.com/pydata-book/owc7z.png)
#
# ![](http://oydgk2hgw.bkt.clouddn.com/pydata-book/cn2y0.png)



StarcoderdataJupyterScriptsDedupFiltered