如果值包含未转义的逗号,是否有一种简单的方法来解析 Excel、Power Query 或 VBA 中逗号分隔的 Key:Value 对?
Is there a simple way to parse comma separated Key:Value pairs in Excel, Power Query or VBA if the values contain unescaped commas?
我正在处理包含约 22000 条记录的身份数据的 CSV 导出。其中一个字段的标题为 'ExtendedAttributes',该列中的每个单元格都包含一个由逗号分隔的 Key:Value 对引号绑定字符串。文件中的每条记录都有任意数量的扩展属性(最多约 50 个)。我最终的 objective 是将这些扩展属性扩展到 Excel (2016) 中它们自己的列中。我已经有了使用公式、简单 VBA 和最近基于 Power Query 的方法从其他数据扩展到列的解决方案。
然而,我之前的解决方案都是基于易于分隔的 Key:Value 对。在此导出中,ExtendedAttributes 字段具有:
可能包含 unescaped/unquoted 逗号的数值数据。例如
"Key1: Value1, name: surname, forename, Key2: Value2, ... "
可能包含多个逗号分隔值的键,它们也是 unquoted/unescaped。例如
"Key1: Value1, emailAlias: alias1@domain, alias2@domain, alias3@domain, Key2: Value2, ... "
我通常的做法是,Key:Value 对没有这些问题,使用逗号分隔将其分成键值对,将数据转置为行,然后使用冒号分隔按照描述填充我的新列及其值 here in the PowerBI community pages
这在这里不起作用,因为使用逗号分隔会破坏值。
有没有一种直接的方法可以使用(理想情况下)Power Query 将其解析为构成 Key:Value 对?也很高兴使用 VBA 或基于公式的解决方案。
我的本能方法是尝试识别包含冒号的子字符串,并在它们前面加上一个唯一字符,然后可以将其用作分隔符。 (数据也可能包含未转义的冒号并非不可能,但我很乐意假设它不会)但认识到这可能是一种不必要的复杂方法,我不确定如何最好地做到这一点。
我很乐意将多个逗号分隔项的值作为一个单元保存(我稍后会处理这个问题)。
示例数据:
"Key1: Value1, name: surname, forename, emailAlias: alias1@domain, alias2@domain, alias3@domain, Key2: Value2, ... "
我想最终得到一些让我像这样处理数据的东西,也许使用!作为示例,我可以将其用作分隔符:
"Key1: Value1!name: surname, forename!emailAlias: alias1@domain, alias2@domain, alias3@domain!Key2: Value2!..."
我无权访问原始数据(供应商控制的系统)并且公司桌面上的数据处理工具有限(Excel 2016,VBA,PQ)。
感谢任何帮助。
你没有说什么文件记录不计入“ExtendedAttribute字段”类别...我准备了一个函数可以分离你讨论的那个区域。请使用下一个代码:
Function separateKeys(x As String, sep As String) As String
Dim arr1, arr2, i As Long, k As Long
arr1 = Split(x, ": ")
ReDim arr2(UBound(arr1))
For i = 0 To UBound(arr1) - 1
If arr1(i + 1) = arr1(UBound(arr1)) Then Exit For
arr2 = Split(arr1(i + 1), " ")
arr2(UBound(arr2) - 1) = Replace(arr2(UBound(arr2) - 1), ",", sep)
arr1(i + 1) = Join(arr2, " ")
Next
separateKeys = Replace(Join(arr1, ":"), sep & " ", sep)
End Function
上述函数可以(可能)以跳过文件其余部分计算的方式进行调整,或者也可以转换 sep
字符中的每个逗号(使用 Replace
即可)。
为了测试以上功能,请使用下一个测试Sub
:
Sub testSepKeys()
Dim x As String, sep As String
sep = "|" 'you can try something else, but improbable to appear in the processed text
x = "Key1: Value1, name: surname, forename, emailAlias: alias1@domain, alias2@domain, alias3@domain, Key2: Value2, Value3, key3: Val1, Val2"
Debug.Print separateKeys(x, sep)
End Sub
像全局工作方式一样,我建议在行分隔符上拆分文件,然后使用上述(改编的)函数处理所有数组元素(行),最后在行分隔符上加入它。
新创建的文件应使用 Workbooks.OpenText
、DataType:=xlDelimited
、OtherChar:=sep
.
打开
请测试以上功能并发送一些反馈。
在Power Query中,您可以定义一个函数Partition
如下:
let
Output = (str as text, sep as text) as text =>
Text.RemoveRange(
Text.Replace(
Text.Combine(
List.Transform(
Text.Split(str, " "),
each if Text.Contains(_, ":") then sep & _ else _
),
" "
), ", " & sep, sep
),
0, Text.Length(sep)
)
in
Output
使用分隔符的文本转换示例 !
起始文字:
Key1: Value1, name: surname, forename, emailAlias: alias1@domain
- 根据空格将字符串拆分为列表
Key1:
Value1,
name:
surname,
forename,
emailAlias:
alias1@domain
- 在任何包含
:
的列表项前加上分隔符 !
!Key1:
Value1,
!name:
surname,
forename,
!emailAlias:
alias1@domain
- 将列表组合回字符串
!Key1: Value1, !name: surname, forename, !emailAlias: alias1@domain
- 将
, !
替换为!
!Key1: Value1!name: surname, forename!emailAlias: alias1@domain
- 删除第一个分隔符
Key1: Value1!name: surname, forename!emailAlias: alias1@domain
定义此函数后,您可以在类似于
的列转换中调用它
= Table.TransformColumns(#"Prev Step", {{"ColName", each Partition(_,"!") , type text}})
我正在处理包含约 22000 条记录的身份数据的 CSV 导出。其中一个字段的标题为 'ExtendedAttributes',该列中的每个单元格都包含一个由逗号分隔的 Key:Value 对引号绑定字符串。文件中的每条记录都有任意数量的扩展属性(最多约 50 个)。我最终的 objective 是将这些扩展属性扩展到 Excel (2016) 中它们自己的列中。我已经有了使用公式、简单 VBA 和最近基于 Power Query 的方法从其他数据扩展到列的解决方案。
然而,我之前的解决方案都是基于易于分隔的 Key:Value 对。在此导出中,ExtendedAttributes 字段具有:
可能包含 unescaped/unquoted 逗号的数值数据。例如
"Key1: Value1, name: surname, forename, Key2: Value2, ... "
可能包含多个逗号分隔值的键,它们也是 unquoted/unescaped。例如
"Key1: Value1, emailAlias: alias1@domain, alias2@domain, alias3@domain, Key2: Value2, ... "
我通常的做法是,Key:Value 对没有这些问题,使用逗号分隔将其分成键值对,将数据转置为行,然后使用冒号分隔按照描述填充我的新列及其值 here in the PowerBI community pages
这在这里不起作用,因为使用逗号分隔会破坏值。
有没有一种直接的方法可以使用(理想情况下)Power Query 将其解析为构成 Key:Value 对?也很高兴使用 VBA 或基于公式的解决方案。
我的本能方法是尝试识别包含冒号的子字符串,并在它们前面加上一个唯一字符,然后可以将其用作分隔符。 (数据也可能包含未转义的冒号并非不可能,但我很乐意假设它不会)但认识到这可能是一种不必要的复杂方法,我不确定如何最好地做到这一点。
我很乐意将多个逗号分隔项的值作为一个单元保存(我稍后会处理这个问题)。
示例数据:
"Key1: Value1, name: surname, forename, emailAlias: alias1@domain, alias2@domain, alias3@domain, Key2: Value2, ... "
我想最终得到一些让我像这样处理数据的东西,也许使用!作为示例,我可以将其用作分隔符:
"Key1: Value1!name: surname, forename!emailAlias: alias1@domain, alias2@domain, alias3@domain!Key2: Value2!..."
我无权访问原始数据(供应商控制的系统)并且公司桌面上的数据处理工具有限(Excel 2016,VBA,PQ)。 感谢任何帮助。
你没有说什么文件记录不计入“ExtendedAttribute字段”类别...我准备了一个函数可以分离你讨论的那个区域。请使用下一个代码:
Function separateKeys(x As String, sep As String) As String
Dim arr1, arr2, i As Long, k As Long
arr1 = Split(x, ": ")
ReDim arr2(UBound(arr1))
For i = 0 To UBound(arr1) - 1
If arr1(i + 1) = arr1(UBound(arr1)) Then Exit For
arr2 = Split(arr1(i + 1), " ")
arr2(UBound(arr2) - 1) = Replace(arr2(UBound(arr2) - 1), ",", sep)
arr1(i + 1) = Join(arr2, " ")
Next
separateKeys = Replace(Join(arr1, ":"), sep & " ", sep)
End Function
上述函数可以(可能)以跳过文件其余部分计算的方式进行调整,或者也可以转换 sep
字符中的每个逗号(使用 Replace
即可)。
为了测试以上功能,请使用下一个测试Sub
:
Sub testSepKeys()
Dim x As String, sep As String
sep = "|" 'you can try something else, but improbable to appear in the processed text
x = "Key1: Value1, name: surname, forename, emailAlias: alias1@domain, alias2@domain, alias3@domain, Key2: Value2, Value3, key3: Val1, Val2"
Debug.Print separateKeys(x, sep)
End Sub
像全局工作方式一样,我建议在行分隔符上拆分文件,然后使用上述(改编的)函数处理所有数组元素(行),最后在行分隔符上加入它。
新创建的文件应使用 Workbooks.OpenText
、DataType:=xlDelimited
、OtherChar:=sep
.
请测试以上功能并发送一些反馈。
在Power Query中,您可以定义一个函数Partition
如下:
let
Output = (str as text, sep as text) as text =>
Text.RemoveRange(
Text.Replace(
Text.Combine(
List.Transform(
Text.Split(str, " "),
each if Text.Contains(_, ":") then sep & _ else _
),
" "
), ", " & sep, sep
),
0, Text.Length(sep)
)
in
Output
使用分隔符的文本转换示例 !
起始文字:
Key1: Value1, name: surname, forename, emailAlias: alias1@domain
- 根据空格将字符串拆分为列表
Key1:
Value1,
name:
surname,
forename,
emailAlias:
alias1@domain
- 在任何包含
:
的列表项前加上分隔符!
!Key1:
Value1,
!name:
surname,
forename,
!emailAlias:
alias1@domain
- 将列表组合回字符串
!Key1: Value1, !name: surname, forename, !emailAlias: alias1@domain
- 将
, !
替换为!
!Key1: Value1!name: surname, forename!emailAlias: alias1@domain
- 删除第一个分隔符
Key1: Value1!name: surname, forename!emailAlias: alias1@domain
定义此函数后,您可以在类似于
的列转换中调用它= Table.TransformColumns(#"Prev Step", {{"ColName", each Partition(_,"!") , type text}})