Python Pandas - 电子邮件列包含带有分隔符的值
Python Pandas - Email column has values with the delimiter on it
所以我的工作中有这么大的 .csv,看起来像这样:
Name| Adress| Email| Paid Value
John| x street | John@dmail.com| 0|
Chris| c street | Chris@dmail.com| 100|
Rebecca| y street| RebeccaFML|@dmail.com|177|
Bozo | z street| BozoSMH|@yahow.com|976|
如您所见,.csv 是用管道分隔的,最后两个人的电子邮件中有管道,导致格式问题。
只有 2 个客户有这个问题,但这些家伙每个月都会有越来越多的条目,我们必须在 csv 中手动找到它们并手动更改电子邮件。这是一个非常无聊和耗时的过程,因为文件很大。
我们使用 python 来处理数据,我研究了一下,找不到任何可以帮助我的东西,有什么想法吗?
编辑:所以我想要的是一种通过代码自动更改此电子邮件地址的方法(如 RebeccaFML|@dmail.com -> RebeccaFML@dmail.com)。它确实需要 pandas 或任何东西,我接受任何类型的想法。最主要的是我只知道如何在我读取 python 中的文件后进行替换,但是由于这些寄存器中有管道,它们无法正确读取。
提前联系
为自定义行创建生成器
这里应该将电子邮件列设置在第 3 位,但你可以调整它
import pandas
def rows(path: str, sep: str = '|'):
with open(path) as f:
header = [*f.readline().split(sep), None]
for row in f:
row = row.rsplit('\n', 1)[0].split(sep)
if len(row) > len(header):
yield [*row[:2], ''.join((row[2], row[3])), *row[4:]]
else:
yield row
pandas.DataFrame(rows('data.csv'))
您可以在 read_csv
中将正则表达式作为分隔符传递。 \|\s*(?!\@)
将在管道上拆分(可能后跟空格),但排除后跟 at 符号的管道。您随后可以使用 replace
:
删除剩余的管道
import pandas as pd
import io
data = '''Name| Adress| Email| Paid Value
John| x street | John@dmail.com| 0|
Chris| c street | Chris@dmail.com| 100|
Rebecca| y street| RebeccaFML|@dmail.com|177|
Bozo | z street| BozoSMH|@yahow.com|976|'''
df = pd.read_csv(io.StringIO(data), sep = r'(?<!\@)\s*\|\s*(?!\@)', engine='python',index_col=False,usecols=range(4)).replace('\|','', regex=True)
输出:
Name
Adress
Email
Paid Value
0
John
x street
John@dmail.com
0
1
Chris
c street
Chris@dmail.com
100
2
Rebecca
y street
RebeccaFML@dmail.com
177
3
Bozo
z street
BozoSMH@yahow.com
976
一种方法是使用正则表达式删除文本文件中麻烦的管道 (|
):
import re
data = '''Name| Adress| Email| Paid Value
John| x street | Jo|hn@dmail.com| 0|
Chris| c street | |Chris@dmail.com| 100|
Rebecca| y street| RebeccaFML|@dmail.com|177|
Bozo | z street| BozoSMH|@yahow.com|976|'''
pattern = re.compile(r"""(\|[^|]+?) # the previous pipe, i.e. a pipe followed by one or more not pipe characters
\| # the troublesome pipe
([^|]*?@.+?\|) # the rest of the email until the next pipe """, re.VERBOSE)
res = pattern.sub(r"", data)
print(res)
输出
Name| Adress| Email| Paid Value
John| x street | John@dmail.com| 0|
Chris| c street | Chris@dmail.com| 100|
Rebecca| y street| RebeccaFML@dmail.com|177|
Bozo | z street| BozoSMH@yahow.com|976|
注意为了测试在 data
值中添加了额外的管道。请参阅 here 以获得额外的解释和调试。
所以我的工作中有这么大的 .csv,看起来像这样:
Name| Adress| Email| Paid Value
John| x street | John@dmail.com| 0|
Chris| c street | Chris@dmail.com| 100|
Rebecca| y street| RebeccaFML|@dmail.com|177|
Bozo | z street| BozoSMH|@yahow.com|976|
如您所见,.csv 是用管道分隔的,最后两个人的电子邮件中有管道,导致格式问题。 只有 2 个客户有这个问题,但这些家伙每个月都会有越来越多的条目,我们必须在 csv 中手动找到它们并手动更改电子邮件。这是一个非常无聊和耗时的过程,因为文件很大。
我们使用 python 来处理数据,我研究了一下,找不到任何可以帮助我的东西,有什么想法吗?
编辑:所以我想要的是一种通过代码自动更改此电子邮件地址的方法(如 RebeccaFML|@dmail.com -> RebeccaFML@dmail.com)。它确实需要 pandas 或任何东西,我接受任何类型的想法。最主要的是我只知道如何在我读取 python 中的文件后进行替换,但是由于这些寄存器中有管道,它们无法正确读取。
提前联系
为自定义行创建生成器 这里应该将电子邮件列设置在第 3 位,但你可以调整它
import pandas
def rows(path: str, sep: str = '|'):
with open(path) as f:
header = [*f.readline().split(sep), None]
for row in f:
row = row.rsplit('\n', 1)[0].split(sep)
if len(row) > len(header):
yield [*row[:2], ''.join((row[2], row[3])), *row[4:]]
else:
yield row
pandas.DataFrame(rows('data.csv'))
您可以在 read_csv
中将正则表达式作为分隔符传递。 \|\s*(?!\@)
将在管道上拆分(可能后跟空格),但排除后跟 at 符号的管道。您随后可以使用 replace
:
import pandas as pd
import io
data = '''Name| Adress| Email| Paid Value
John| x street | John@dmail.com| 0|
Chris| c street | Chris@dmail.com| 100|
Rebecca| y street| RebeccaFML|@dmail.com|177|
Bozo | z street| BozoSMH|@yahow.com|976|'''
df = pd.read_csv(io.StringIO(data), sep = r'(?<!\@)\s*\|\s*(?!\@)', engine='python',index_col=False,usecols=range(4)).replace('\|','', regex=True)
输出:
Name | Adress | Paid Value | ||
---|---|---|---|---|
0 | John | x street | John@dmail.com | 0 |
1 | Chris | c street | Chris@dmail.com | 100 |
2 | Rebecca | y street | RebeccaFML@dmail.com | 177 |
3 | Bozo | z street | BozoSMH@yahow.com | 976 |
一种方法是使用正则表达式删除文本文件中麻烦的管道 (|
):
import re
data = '''Name| Adress| Email| Paid Value
John| x street | Jo|hn@dmail.com| 0|
Chris| c street | |Chris@dmail.com| 100|
Rebecca| y street| RebeccaFML|@dmail.com|177|
Bozo | z street| BozoSMH|@yahow.com|976|'''
pattern = re.compile(r"""(\|[^|]+?) # the previous pipe, i.e. a pipe followed by one or more not pipe characters
\| # the troublesome pipe
([^|]*?@.+?\|) # the rest of the email until the next pipe """, re.VERBOSE)
res = pattern.sub(r"", data)
print(res)
输出
Name| Adress| Email| Paid Value
John| x street | John@dmail.com| 0|
Chris| c street | Chris@dmail.com| 100|
Rebecca| y street| RebeccaFML@dmail.com|177|
Bozo | z street| BozoSMH@yahow.com|976|
注意为了测试在 data
值中添加了额外的管道。请参阅 here 以获得额外的解释和调试。