64

我似乎在电子表格上花费了大量时间来研究以下公式:

="some text '" & A1 & "', more text: '" & A2 &" etc."

使用 printf 或 String.Format 字符串会快得多

=String.Format ("Some text '{0}', more text: '{1}'",A1,A2)

Excel中是否有类似的内容,或者我可以调用CLR吗?

4

7 回答 7

90

不,但是您可以通过将以下内容添加到 VBA 模块来简单地创建一个简单的模型:

Public Function printf(ByVal mask As String, ParamArray tokens()) As String
    Dim i As Long
    For i = 0 To ubound(tokens)
        mask = replace$(mask, "{" & i & "}", tokens(i))
    Next
    printf = mask
End Function

...

=printf("Some text '{0}', more text: '{1}'", A1, A2)
于 2013-06-21T11:12:11.750 回答
18

不是真的 - 有CONCATENATE功能:

=CONCATENATE("some text '", A1, "', more text: '", A2, " etc.")

&但在我看来,它并不比使用更好。

于 2013-06-21T11:10:52.243 回答
15

我已经更新了 Alex 的代码,以便您可以%s在每次插入时使用。

代替:

=printf("Some text '{0}', more text: '{1}'", A1, A2)

您可以使用:

=printf("Some text '%s', more text: '%s'", A1, A2) 

就像原来的一样sprintf

更新后的代码:

Public Function Printf(ByVal mask As String, ParamArray tokens()) As String
   Dim i As Long

   For i = 0 To UBound(tokens)          
      mask = Replace$(mask, "%s", tokens(i), , 1)
   Next

   Printf = mask

End Function
于 2015-08-12T18:20:02.763 回答
13

您可以使用 TEXT 功能 -

您可以像我一样将格式字符串存储在单元格中的某个位置。

"BUY "#" CREDITS"我的D1 单元格中有 的值。在我的 A5 单元格中,我的值为 5000。当我想显示我使用的格式化字符串时=TEXT(A5, $D$1)

它将单元格的值设置为 BUY 5000 CREDITS。

于 2014-04-29T14:37:59.127 回答
3

@AlexK提供的“防弹”版本,允许:

  • 转义令牌printf("{0}{1}", "test {1}", 2) -> "test {1}2" (NOT "test 22")
  • 位置语法printf("{}{}", "a", "b") -> "ab"
Public Function printf(ByVal mask As String, ParamArray tokens() As Variant) As String
    Dim i As Long
    For i = 0 To UBound(tokens)
        Dim escapedToken As String
        escapedToken = Replace$(tokens(i), "}", "\}") 'only need to replace closing bracket since {i\} is already invalid
        If InStr(1, mask, "{}") <> 0 Then
            'use positional mode {}
            mask = Replace$(mask, "{}", escapedToken, Count:=1)
         
        Else
            'use indexed mode {i}
            mask = Replace$(mask, "{" & i & "}", escapedToken)
        
        End If
    Next
    mask = Replace$(mask, "\}", "}")
    printf = mask
End Function

用法和以前一样:

=printf("Some text '{0}', more text: '{1}'", A1, A2)

或位置(从左到右)

=printf("Some text '{}', more text: '{}'", A1, A2)

请注意,正如@CristianBuse 在评论中指出的那样,这个实现仍然会被一个面具绊倒,比如{0\}{1}导致{0}{foo}not {0\}{foo},解决方法是不要\}在你的面具中使用。


*使用混合语法的行为 `=printf("Some text '{}', more text: '{1}'", A1, A2)` 是未定义的,但替换从左到右所以 `"{}{2}{ 1}"` 等价于`"{0}{2}{1}"`。`"{}{1}{}"` 不会做你想做的事
于 2021-06-06T11:58:35.613 回答
2

好的,我提供了一个VBA 解决方案,但这是一个使用相对较新的 LAMBDA 函数的纯 Excel 版本,没有 VBA


注意我已经在 Code Review 上发布了一个用逗号分隔的 args的替代版本PRINTF(mask, arg1, arg2, ...),但是我会尽量保持这个版本的规范和最新,因为有新的更好的选项可用


为此,我创建了一个带有签名的命名函数,printf(mask, tokensArray)其中:

  • mask是您要格式化的字符串,包含位置{}或索引{i}插值位置。
  • tokensArray是要替换的值的集合,以一维范围(行或列)、数组(硬编码或从函数返回)或单个值的形式提供。

...并返回一个格式化的字符串。从像这样的单元格调用:

工具提示

用法

=printf("Some text '{1}', more text: '{2}'", A1:A2) //continuous 1D row/col
=printf("Some text '{1}', more text: '{2}'", {"foo","bar"}) //hardcoded array
=printf("Single Value {1}", "foo")

或使用位置参数(从左到右)

=printf("Some text '{}', more text: '{}'", A1:A2)

通过在名称管理器中输入这两个函数来定义它们(有关详细说明,请参阅LAMBDA 函数MSDN 文档,尽管我确定这个链接会死...):

参数 价值
姓名 替换递归
范围 工作簿
评论 递归地将 {} 或 {i} 替换为令牌列表中的令牌,它会一一转义,将 } 留在结果字符串中
=LAMBDA(mask,tokens,i,tokenCount, IF(i >tokenCount, mask, LET(token, INDEX(tokens,i),escapedToken,SUBSTITUTE(token,"}", "\}"),inIndexedMode,ISERROR(FIND("{}",mask,1)),substituted, IF(inIndexedMode, SUBSTITUTE(mask,"{"&i&"}", escapedToken),SUBSTITUTE(mask, "{}", escapedToken,1) ),ReplaceRecursive(substituted,tokens,i+1,tokenCount))))
=LAMBDA(
    mask,
    tokens,
    i,
    tokenCount,
    IF(
        i > tokenCount,
        mask,
        LET(
            token,
            INDEX(
                tokens,
                i
            ),
            escapedToken,
            SUBSTITUTE(
                token,
                "}",
                "\}"
            ),
            inIndexedMode,
            ISERROR(
                FIND(
                    "{}",
                    mask,
                    1
                )
            ),
            substituted,
            IF(
                inIndexedMode,
                SUBSTITUTE(
                    mask,
                    "{" & i & "}",
                    escapedToken
                ),
                SUBSTITUTE(
                    mask,
                    "{}",
                    escapedToken,
                    1
                )
            ),
            ReplaceRecursive(
                substituted,
                tokens,
                i + 1,
                tokenCount
            )
        )
    )
)
参数 价值
姓名 打印
范围 工作簿
评论 printf(mask: str, tokensArray: {array,} | range | str ) -> str | 掩码:将标记替换为例如“Hello {},{}”或“Hello {2},{1}”(1-indexed)的字符串| tokensArray:一维范围或令牌数组,例如 "world" 或 {"foo","bar"} 或 A1:A5
=LAMBDA(mask,tokensArray,LET(r,ROWS(tokensArray), c, COLUMNS(tokensArray), length, MAX(r,c), IF(AND(r>1, c>1), "tokensArray must be 1 dimensional", SUBSTITUTE(ReplaceRecursive(mask, tokensArray, 1, length), "\}","}"))))
=LAMBDA(
    mask,
    tokensArray,
    LET(
        r,
        ROWS(
            tokensArray
        ),
        c,
        COLUMNS(
            tokensArray
        ),
        length,
        MAX(
            r,
            c
        ),
        IF(
            AND(
                r > 1,
                c > 1
            ),
            "tokensArray must be 1 dimensional",
            SUBSTITUTE(
                ReplaceRecursive(
                    mask,
                    tokensArray,
                    1,
                    length
                ),
                "\}",
                "}"
            )
        )
    )
)

我敢肯定,Excel 的 LAMBDA 函数会有所改进,使编写起来更容易,但我认为这种递归方法现在很好。

于 2021-09-21T08:52:11.990 回答
1

有趣的问题......我也在想同样的......如何构建一个字符串而不必在数字之间的某些单个部分中截断长句。

而且因为我不想创建 VBA 函数(这会更聪明),所以这是我的解决方案......

SUBSTITUTE(P253;O252;"A1A";1)

在哪里

  • P253 是我的长字符串,#1 标签为“A1A”
  • O252 是 #1 标签的值

依此类推...(即使不是我需要)如果其他值...

=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(P253;O251;"A1A";1);O252;"A2A";1);O253;"A2A";1)

好吧,我想,即使在#C 中,sprintf(....%s, %s, %d..) 也应该有多重替换原语函数。

于 2016-04-20T12:48:08.120 回答