拆分字符串无分隔符,具有限制的字段名称和内容
Posted
技术标签:
【中文标题】拆分字符串无分隔符,具有限制的字段名称和内容【英文标题】:split string no delimiter with limitative field names and content 【发布时间】:2020-03-20 11:14:11 【问题描述】:我有一个带有 bankmutations 的数据框。 数据框包含一个描述列。在此列中,有限制性的字段名称及其内容。 它看起来像:
AAm.loc[0, ’OmsBank'] => ‘ fieldname1: content fn1 fieldname3: content fn3 ‘
AAm.loc[1, ’OmsBank'] => ‘ fieldname5: content fn5 fieldname2: content fn2 ‘
如果有解决这个问题的一般方法(分解字段名和内容中的长字符串),我做了很多谷歌搜索。到目前为止,还没有找到简单的解决方案。
我可以使用双空格作为分隔符来分割,但在字段内容内也有双空格。所以这不是一个有效的选择。尝试将 split 与列表/数组一起使用,但也没有运气。
到目前为止,我已经创建了一个小的第二个数据框,其中包含限制性字段名、字段名的起始位置、内容的起始位置和内容的结束位置。
我遍历银行对账单的行,检查存在哪些字段名,并将开始标签的位置和开始内容存储在小数据框中 我按字段名的位置对小数据框进行排序,重置索引,然后我可以确定内容的结束位置(下一个字段名的开始)。 最后一个字段名没有下一个字段名。所以我必须将描述字符串的长度存储为结束值。 然后我可以将特定元素的内容存储在银行对帐单数据框中。
我觉得它可以做得更“pythonic”和高效,vectorise,lambda函数? 如果有人有建议,我将不胜感激。这个问题的一般解决方案也可以帮助其他人。
到目前为止我的代码:
import pandas as pd
# data
tosplit = ['SEPA Inc dl Incassant: blabla Naam: Insurance Machtiging: number Omschrijving: Rel.nr. number2 IBAN: iban#',
'SEPA Overboeking IBAN: iban# BIC: bic# Naam: blabla Omschrijving: Refund Kenmerk: refcode',
'SEPA iDEAL IBAN: iban# BIC: bic# Naam: seller Omschrijving: description double space Kenmerk: refcode',
'SEPA iDEAL IBAN: iban# BIC: bic# Naam: city Omschrijving: citytax']
AAm = pd.DataFrame(tosplit, columns= ['OmsBank'])
AAm['Naam'] = ''
AAm['Oms'] = ''
AAm
# field list
fld = [' IBAN: ', ' BIC: ', ' Naam: ', ' Omschrijving: ', ' Kenmerk: ', ' Referentie: ', ' Machtiging: ', ' Incassant: ']
fld.sort()
# store field list in dataframe and add columns for position
fld= pd.DataFrame(fld, columns = ['fldnm'] )
ser= [0]*len(fld)
fld = fld.assign(bgn = ser, bgc = ser, end = ser )
# loop through AAm (dataframe with bankmutations) and proces data
for i in AAm.index:
# search for fieldnames and store postion (begin of fieldname and begin of fieldcontent) if the are found
for j in fld.index:
temp = AAm.loc[i, 'OmsBank'].find(fld.loc[j,'fldnm'])
if temp == -1:
temp2 = -1
else:
temp2 = temp+len(fld.loc[j,'fldnm'])
fld.loc[j,'bgn'] = temp
fld.loc[j,'bgc'] = temp2
# order by postion and reset index
fld = fld.sort_values(by ='bgc')
fld.reset_index(drop=True, inplace = True)
# establish end of content position. For the last one it is length general string
for j in fld.index:
if (fld.loc[j, 'bgn']>0) & (j < len(fld)-1):
fld.loc[j, 'end'] = fld.loc[(j+1), 'bgn']
fld.loc[len(fld)-1, 'end'] = len(AAm.loc[i, 'OmsBank'])
# store start/end of relevant field content in AAm
nm_om = fld[(fld['fldnm'] == ' Naam: ') | (fld['fldnm'] == ' Omschrijving: ')]
nm_om.reset_index(drop=True, inplace = True)
AAm.loc[i,'Naam'] = AAm.loc[i,'OmsBank'][nm_om.loc[0, 'bgc']:nm_om.loc[0, 'end']].strip()
AAm.loc[i,'Oms'] = AAm.loc[i,'OmsBank'][nm_om.loc[1, 'bgc']:nm_om.loc[1, 'end']].strip()
#reset values in fieldlist
fld[['bgn', 'bgc', 'end']]=0
【问题讨论】:
解决(更复杂的)问题的最佳实践是提供所谓的“可重现”场景,人们可以在他们的 IDE 中复制和粘贴您的数据框 + 代码并遇到相同的问题。对你来说,这意味着包含一个带有pd.DataFrame
的数据集,这样人们就可以立即以正确的格式获取数据,因为这对你的问题非常重要。例如,请参阅我的 questions 之一
@Erfan:这是一个相当大的集合。我的代码有效,但我认为它远非最佳。我将尝试添加一个小数据框以使其可重现
是的,我们的想法是将您的问题分解为一个小的示例数据集,而不是包含整个数据集。我也会把你的问题分解成小部分,现在你发布了你的整个代码,这会吓跑大多数人,因为他们不想通过 80 行代码来调试。
您提供了 2 行的描述。生成数据帧提取的一种简单方法是 df.iloc[:10].to_dict(orient='list')
:它提供前 10 行的可复制粘贴内容(将切片调整为相关的内容)
【参考方案1】:
我发现了我的问题并发现了正则表达式。您可以搜索所有类型的(文本)模式。我的模式是'字段名:字段值 secondfieldname:第二个字段值'。 您可以将这些块放在括号中并使用 group(number) 引用它们,其中 0 是整个搜索字符串,1 是第一组等。
其中一个示例行是:
tosplit = 'SEPA Inc dl Incassant: blabla Naam: Insurance Machtiging: number Omschrijving: Rel.nr. number2 IBAN: iban#'
导入正则表达式并搜索字符串中的模式进行拆分,并使用括号将它们分组:
import re
splitted = re.search(r'( Naam: )(.*)( Machtiging: )', tosplit)
名称内容可以通过
轻松获取name = splitted.group(2)
【讨论】:
以上是关于拆分字符串无分隔符,具有限制的字段名称和内容的主要内容,如果未能解决你的问题,请参考以下文章