我将我的Verizon账单中的谈话活动内容提取到一个文本文件中。我想对数据做一些分析。我更喜欢使用powershell、python或bash。任何关于如何将以下内容转换为csv的想法:
Jan 6 12:30 PM不可用拉斯维加斯,内华达州来电,CL 2
Jan 7 11:06 AM 697.732.5672 Reno,NV Victorvl,CA 30
Jan 4 3:26 PM 702.792.2189拉斯维加斯,内华达州VM存款,CL 1
Jan 24 4:24 PM 213.302.2581 Sacramento,CA Incoming,CL 105
结果应该是什么样子的示例:
“1月6日12:30 PM",”不可用“,”拉斯维加斯,内华达州“,”来电,CL","2“
"Jan 7 11:06 AM","697.732.5672","Reno,NV","Victorvl,CA","30“
"Jan 4 3:26 PM","702.792.2189",“拉斯维加斯,内华达州”,"VM存款,CL","1“
"Jan 24 4:24 PM","213.302.2581","Sacramento,CA","Incoming,CL","105“
谢谢你的建议。
发布于 2018-10-10 06:48:44
我很犹豫是否在这里发布一个答案,因为问题空间没有明确定义,也没有任何工作来显示你被困在哪里,或者你是否尝试过任何事情。
另一方面,这是一个用Python强调一些基本的字符串解析策略的机会,所以我将把它作为一种带注释的演练,这对阅读这篇文章的人可能会有一些好处。
我采用的方法是将每个内容行拆分为空格分隔的元素,然后组合适当的部分。
让我们假设输入的data看起来与posted完全一样,内容行之间用空格分隔。然后,data.split("\n")将生成一个包含7个元素的列表:4行内容和3行空字符串(''):
data.split("\n")
['Jan 6 12:30 PM Unavailable Las Vegas, NV Incoming, CL 2',
'',
'Jan 7 11:06 AM 697.732.5672 Reno, NV Victorvl, CA 30',
'',
'Jan 4 3:26 PM 702.792.2189 Las Vegas, NV VM Deposit, CL 1',
'',
'Jan 24 4:24 PM 213.302.2581 Sacramento, CA Incoming, CL 105'] 我们可以通过检查len(x)来删除空字符串行(如果为len == 0,则计算结果为False ),然后使用单个空格split()其余行。
lines = [x.split() for x in data.split("\n") if len(x)]
lines
[['Jan', '6', '12:30', 'PM', 'Unavailable', 'Las', 'Vegas,', 'NV', 'Incoming,', 'CL', '2'],
['Jan', '7', '11:06', 'AM', '697.732.5672', 'Reno,', 'NV', 'Victorvl,', 'CA', '30'],
['Jan', '4', '3:26', 'PM', '702.792.2189', 'Las', 'Vegas,', 'NV', 'VM', 'Deposit,', 'CL', '1'],
['Jan', '24', '4:24', 'PM', '213.302.2581', 'Sacramento,', 'CA', 'Incoming,', 'CL', '105']]我将假设每条记录中的三个字段始终具有相同数量的元素:日期/时间、IP地址和最终数字(call duration?)。这使得硬编码我们应该为这些字段join()的元素的数量变得很容易。
有问题的字段是位置字段,因为字符串块的数量可能因每个位置而异。例如,在上面的拆分操作之后,"Reno, NV"变成了一个2元素列表(["Reno,", "NV"])。但是"Las Vegas, NV"在split之后变成了["Las", "Vegas,", "NV"],有3个元素。这意味着我们不能只硬编码在join中使用的每组位置字符串的开始和结束索引。
我们在这里可以使用的一个技巧是在一组位置字符串的最后一个字符串中添加一个特殊字符。然后,我们可以在开始时将所有两个位置字段join在一起,然后在特殊字符上执行split。这有点不雅观,但会把工作做好的。
如何确定哪个字符串块是一组位置字符串中的最后一个?似乎可以安全地假设,如果一个字符串块以逗号(例如'Vegas,'或'Reno,')结尾,那么下一个字符串块将是状态缩写,这是该位置集中的最后一个。我们可以在“逗号块”后面的块中添加一个*标记,如下所示:
for i, elem in enumerate(line):
if elem[-1] == ",":
line[i+1] += "*"然后,在我们对两个位置字符串集(在原始数据中相邻)执行了拆分之后,我们可以对*执行另一次拆分来分隔它们。
下面是完整的解决方案:
lines = [x.split() for x in data.split("\n") if len(x)]
grouped = []
for line in lines:
for i, elem in enumerate(line):
if elem[-1] == ",":
line[i+1] += "*"
grp = [' '.join([str(x) for x in line[:4]]),
str(line[4]),
' '.join([str(x) for x in line[5:]])]
grouped.append(grp[:2] + grp[2].split("* "))输出:
grouped
[['Jan 6 12:30 PM', 'Unavailable', 'Las Vegas, NV', 'Incoming, CL', '2'],
['Jan 7 11:06 AM', '697.732.5672', 'Reno, NV', 'Victorvl, CA', '30'],
['Jan 4 3:26 PM', '702.792.2189', 'Las Vegas, NV', 'VM Deposit, CL', '1'],
['Jan 24 4:24 PM', '213.302.2581', 'Sacramento, CA', 'Incoming, CL', '105']]您可以将其存储为CSV,使用您喜欢的任何I/O方法。
(国际海事组织,熊猫让它变得简单:pd.DataFrame(grouped).to_csv("records.csv", index=False))
发布于 2018-10-10 07:04:49
这段代码使用正则表达式分解记录,创建一个新对象,然后将其导出到CSV文件。
[regex]$rx = '(?<ts>\S+\s\S+\s\S+\s\S+)\s+(?<number>\S+)\s+(?<citystate>[^,]*,\s\S{2})\s+(?<direction>[^,]*, \S{2})\s+(?<minutes>\d*)'
Get-Content -Path '.\phonebill.txt' |
ForEach-Object {
$m = $rx.Match($_)
$record = [PSCustomObject][ordered]@{
Timestamp = $m.groups['ts'].Value
Number = $m.groups['number'].Value
CityState = $m.groups['citystate'].Value
Direction = $m.groups['direction'].Value
Minutes = $m.groups['minutes'].Value
}
$record | Export-Csv -Path '.\phonebill.csv' -Append -Encoding ascii -NoTypeInformation
}它会产生以下输出。
"Timestamp","Number","CityState","Direction","Minutes"
"Jan 6 12:30 PM","Unavailable","Las Vegas, NV","Incoming, CL","2"
"Jan 7 11:06 AM","697.732.5672","Reno, NV","Victorvl, CA","30"
"Jan 4 3:26 PM","702.792.2189","Las Vegas, NV","VM Deposit, CL","1"
"Jan 24 4:24 PM","213.302.2581","Sacramento, CA","Incoming, CL","105"根据@TheMadTechnician和@mklement0的好建议进行了修订。
[regex]$rx = '(?<ts>\S+\s\S+\s\S+\s\S+)\s+(?<number>\S+)\s+(?<citystate>[^,]*,\s\S{2})\s+(?<direction>[^,]*, \S{2})\s+(?<minutes>\d*)'
Get-Content -Path '.\phonebill.txt' |
ForEach-Object {
if ($_ -match $rx) {
[PSCustomObject]@{
Timestamp = $Matches.ts
Number = $Matches.number
CityState = $Matches.citystate
Direction = $Matches.direction
Minutes = $Matches.minutes
}
}
} |
Export-Csv -Path '.\phonebill.csv' -Encoding ascii -NoTypeInformation发布于 2018-10-10 14:44:28
这里有一些python可以做到这一点,RE应该可以移植到其他几种语言上:
import re
with open('gash.txt') as f:
for line in f:
m = re.match(r"(.+[AP]M) ((?:Unavailable)|(?:[0-9\.]+)) ([\w ]+?, [A-Z]{2}) ([\w ]+?, [A-Z]{2}) (\d+)" ,line)
if m:
val = '"'+'","'.join(m.groups())+'"'
print(val)提供:
"Jan 6 12:30 PM","Unavailable","Las Vegas, NV","Incoming, CL","2"
"Jan 7 11:06 AM","697.732.5672","Reno, NV","Victorvl, CA","30"
"Jan 4 3:26 PM","702.792.2189","Las Vegas, NV","VM Deposit, CL","1"
"Jan 24 4:24 PM","213.302.2581","Sacramento, CA","Incoming, CL","105"如果您需要任何解释,请询问。
https://stackoverflow.com/questions/52729693
复制相似问题