在没有VBA的情况下在Excel中拆分字符串(单元格)(例如,对于数组公式)

时间:2014-08-14 19:27:27

标签: excel

我在带有分隔字符串的Excel电子表格中有数据。为简单起见,请考虑"4#8#10"之类的内容,其中包含任意数量的内容。

有没有办法将其拆分为数组以用于数组公式?例如,像SUM(SplitStr(A1,"#"))这样的东西。 (这不起作用 - 只返回"4"。)

有接近这个的好方法吗?我理想的解决方案最终会得到一个数组,就好像用户输入{4,8,10}用于数组公式一样。

我的工作表的应用程序不允许将基于分隔符的文本添加到列中并对其进行求和。如果可能的话,我宁愿不使用VBA,因为我不会成为工作表的主要消费者。

谢谢, 特里

7 个答案:

答案 0 :(得分:14)

要对条目4,8,10求和,您可以使用以下内容:

=SUMPRODUCT(1*TRIM(MID(SUBSTITUTE(A1,"#",REPT(" ",99)),(ROW(OFFSET($A$1,,,LEN(A1)-LEN(SUBSTITUTE(A1,"#",""))+1))-1)*99+((ROW(OFFSET($A$1,,,LEN(A1)-LEN(SUBSTITUTE(A1,"#",""))+1)))=1),99)))

返回的数组是文本数组,因此开头的 1 * 是将它们转换为数字的一种方法

这部分:

TRIM(MID(SUBSTITUTE(A1,"#",REPT(" ",99)),(ROW(OFFSET($A$1,,,LEN(A1)-LEN(SUBSTITUTE(A1,"#",""))+1))-1)*99+((ROW(OFFSET($A$1,,,LEN(A1)-LEN(SUBSTITUTE(A1,"#",""))+1)))=1),99))

返回数组:

{"4";"8";"10"}

前面有1 *:

{4;8;10}

答案 1 :(得分:9)

使用XML功能:

={SUM(FILTERXML("<t><s>" & SUBSTITUTE(A1, "#", "</s><s>") & "</s></t>", "//s"))}

答案 2 :(得分:2)

您的数据位于 B1 B1

=TRIM(MID(SUBSTITUTE($A1,"#",REPT(" ",999)),COLUMNS($A:A)*999-998,999))

并复制。

答案 3 :(得分:2)

关于罗恩·罗森菲尔德(Ron Rosenfeld)的回答以及奥斯汀·威斯默(Austin Wismer)为何对他不起作用的问题,我花了一个小时的大部分时间来分解它,并试图弄清楚它为什么起作用(我认为)。

函数的OFFSET部分正在使用要拆分的文本作为单元格(我的示例):

“危险|坦克|杜比”

并将其复制到数组列中,其高度通过获取单元格中的字符总数来指定

LEN("Haz|Tank|Doub") = 13 characters

减去它后,当定界符被空白“”

代替时,该单元格中的字符总数
LEN(SUBSTITUTE("Haz|Tank|Doub","|","")) =
LEN("HazTankDoub") = 11 characters

其中给出了所引用的单元格中分隔符的数量:

LEN("Haz|Tank|Doub") - LEN(SUBSTITUTE("Haz|Tank|Doub","|","")) = 2

为此添加1:

LEN("Haz|Tank|Doub")-LEN(SUBSTITUTE("Haz|Tank|Doub","|",""))**+1))** 

13 - 11 + 1 = 3

这给出了我们要拆分的单独文本字符串的数量。 结果是OFFSET函数将单元格按3(在我的示例中)复制到单独的行中

“哈兹|坦克|杜比” “危险|坦克|杜布” “危险|坦克|杜比”

OFFSET("Haz|Tank|Doub",,,LEN("Haz|Tank|Doub")-LEN(SUBSTITUTE("Haz|Tank|Doub","|",""))+1))

OFFSET("Haz|Tank|Doub",,,3) = {"Haz|Tank|Doub";"Haz|Tank|Doub";"Haz|Tank|Doub"}

然后将其馈送到ROW函数中,该函数提供范围中每个单元格的行号,这是棘手的地方。

因此,在我的情况下,用分隔符分隔文本的单元格列表中的第一个单元格的行号始于R2,它的OFFSET然后向下复制3行,因此当我将其输入ROW函数时,我得到:

ROW({"Haz|Tank|Doub";"Haz|Tank|Doub";"Haz|Tank|Doub"}) = {2;3;4}

ROW({$R$2:$R$4}) = {2;3;4}

看起来不错,但是再减去1

(ROW(OFFSET($R$2,,,LEN($R$2)-LEN(SUBSTITUTE($R$2,"|",""))+1))-1)

{2;3;4} - 1 = {1;2;3}

好,然后乘以99

(ROW(OFFSET($R$2,,,LEN($R$2)-LEN(SUBSTITUTE($R$2,"|",""))+1))-1) * 99

{1;2;3} * 99 = {99;297;396}

此后,公式将其添加到此

+((ROW(OFFSET($R$2,,,LEN($R$2)-LEN(SUBSTITUTE($R$2,"|",""))+1)))=1)

与最后一部分几乎相同,除了它不减去1并且检查这些结果中的任何一个是否等于1。之所以这样做,是因为假设是您要尝试的单元格的行号拆分成一个数组是1。所以现在,坚持我的数字,会发生以下情况:

((ROW(OFFSET($R$2,,,LEN($R$2)-LEN(SUBSTITUTE($R$2,"|",""))+1)))=1)   
((ROW(OFFSET($R$2,,,13 - 11 + 1)))=1)
((ROW(OFFSET($R$2,,,3)))=1)
((ROW({$R$2:$R$4}))=1)
(({2;3;4})=1)
(({FALSE;FALSE;FALSE})

{99;297;396} + ({FALSE;FALSE;FALSE})
{99;297;396} + ({0;0;0})
{99;297;396}

这作为从中提取文本的起始编号输入到MID函数中,该起始编号是从中提取文本的文本字符串中的字符数。 MID函数浏览的文本是我们想要分割的单元格,但是它首先用99“”空格代替定界符以将它们分隔开。

MID(SUBSTITUTE($R$2,"|",REPT(" ",99)) = "Haz                                Tank                           Doub"

上面两个之间的空格不完全是99个,只是想显示一个表示形式

因此,数组中3行中每行的起始编号为{99; 297; 396}

因此,MID函数将从上述文本字符串的99个字符开始,并在第一行之后提取99个字符。然后它将以297个字符开头,并在此之后提取99个字符。

MID(SUBSTITUTE($R$2,"|",REPT(" ",99)),{99;297;396},99)
MID("Haz                            Tank                           Doub",{99;297;396},99)

MID("Haz                            Tank                           Doub",{99},99)
MID("Haz                            **|Tank                           |**Doub",{99},99)
Tank

MID("Haz                            Tank                           Doub",{297},99)
MID("Haz                            Tank                           **|Doub               
     |**",{297},99)
Doub

MID("Haz                            Tank                           Doub",{396},99)
MID("Haz                            |Tank                          Doub",{396},99)
""

在最后一个字符上,它以396个字符开头,然后以99个字符开头,该字符不包含任何内容,并且不返回任何内容。

现在,如果我的单元格从$ R $ 1行开始,它将执行以下操作:

ROW({$R$1:$R$3}) = {1;2;3}

(ROW(OFFSET($R$1,,,LEN($R$1)-LEN(SUBSTITUTE($R$1,"|",""))+1))-1)

{1;2;3} - 1 = {0;1;2}

(ROW(OFFSET($R$1,,,LEN($R$1)-LEN(SUBSTITUTE($R$1,"|",""))+1))-1) * 99

{0;1;2} * 99 = {0;99;198}

{0;99;198} + ((ROW(OFFSET($R$1,,,LEN($R$1)-LEN(SUBSTITUTE($R$1,"|",""))+1)))=1)   
{0;99;198} + ((ROW(OFFSET($R$1,,,13 - 11 + 1)))=1)
{0;99;198} + ((ROW(OFFSET($R$1,,,3)))=1)
{0;99;198} + ((ROW({$R$1:$R$3}))=1)
{0;99;198} + (({1;2;3})=1)
{0;99;198} + (({TRUE;FALSE;FALSE})
{0;99;198} + {1;0;0}
{1;99;198}

并将其输入MID,可以正确地从1个字符开始,并提取其右侧的所有99个字符:

MID("Haz                            Tank                           Doub",{1;99;198},99)
{Haz;Tank;Doub}

所有这些都说明了我替换了代码中的2件事,以便无论您在工作表中的何处开始都可以这样做:

TRIM(MID(SUBSTITUTE([@Endorsements],"|",REPT(" ",99)),
(ROW(OFFSET([@Endorsements],,,LEN([@Endorsements])-LEN(SUBSTITUTE([@Endorsements],"|",""))+1))-(ROW([@Endorsements])))*99+
((ROW(OFFSET([@Endorsements],,,LEN([@Endorsements])-LEN(SUBSTITUTE([@Endorsements],"|",""))+1)))=(ROW([@Endorsements]))),99))

请注意,[@ Endorsements]对我来说是$ R $ 2,只是单元格位于命名表中,而@对应于表中的同一行,但又对应于另一个命名列,所以我认为$ R2可以替代并且仍然可以使用

TRIM(MID(SUBSTITUTE([@Endorsements],"|",REPT(" ",99)),
(ROW(OFFSET($R2,,,LEN(R$2)-LEN(SUBSTITUTE($R2,"|",""))+1))-(ROW($R2)))*99+
((ROW(OFFSET($R2,,,LEN($R2)-LEN(SUBSTITUTE($R2,"|",""))+1)))=(ROW($R2))),99))

基本上而不是减去1,而是减去要拆分的单元格所在行的行号。根本没有什么变化,所以仍要归功于罗恩(Ron),但我想我会分享,因为我刚发现了它。

答案 4 :(得分:0)

=INDEX(FILTERXML("<t><s>"&SUBSTITUTE(A1,"#","</s><s>")&"</s></t>","//s"),3,1)

因此您可以引用每个实例而无需数组公式。在此实例中,您引用的是第三个实例

答案 5 :(得分:0)

以防万一有人希望这样做但使用Google表格的情况,这是我的操作方法

假设A1包含4#8#10

=ARRAYFORMULA(SPLIT(A1, "#"))

这将创建一个数组,并在列中显示该数组条目。

如果需要将数组显示为行,则可以使用

=ARRAYFORMULA(TRANSPOSE(SPLIT(A1, "#")))

我希望MS Excel中有一个SPLIT公式。

答案 6 :(得分:0)

我使用了上面罗恩的回答,但它给了我一个带有更大列表的空白空间,我不喜欢每个数据的大小有限,所以我根据他的没有这些的类似公式问题。

=MID($A$1,IFERROR(FIND(" ",SUBSTITUTE($A$1,"#"," ",SEQUENCE(LEN($A$1)-LEN(SUBSTITUTE($A$1,"#","")),,0)))+1,1),FIND(" ",SUBSTITUTE($A$1,"#"," ",SEQUENCE(LEN($A$1)-LEN(SUBSTITUTE($A$1,"#","")),,1)))-IFERROR(FIND(" ",SUBSTITUTE($A$1,"#"," ",SEQUENCE(LEN($A$1)-LEN(SUBSTITUTE($A$1,"#","")),,0))),0)-1)