我似乎在电子表格上花费了大量时间来研究以下公式:
="some text '" & A1 & "', more text: '" & A2 &" etc."
使用 printf 或 String.Format 字符串会快得多
=String.Format ("Some text '{0}', more text: '{1}'",A1,A2)
Excel中是否有类似的内容,或者我可以调用CLR吗?
我似乎在电子表格上花费了大量时间来研究以下公式:
="some text '" & A1 & "', more text: '" & A2 &" etc."
使用 printf 或 String.Format 字符串会快得多
=String.Format ("Some text '{0}', more text: '{1}'",A1,A2)
Excel中是否有类似的内容,或者我可以调用CLR吗?
不,但是您可以通过将以下内容添加到 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)
不是真的 - 有CONCATENATE功能:
=CONCATENATE("some text '", A1, "', more text: '", A2, " etc.")
&
但在我看来,它并不比使用更好。
我已经更新了 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
您可以使用 TEXT 功能 -
您可以像我一样将格式字符串存储在单元格中的某个位置。
"BUY "#" CREDITS"
我的D1 单元格中有 的值。在我的 A5 单元格中,我的值为 5000。当我想显示我使用的格式化字符串时=TEXT(A5, $D$1)
。
它将单元格的值设置为 BUY 5000 CREDITS。
@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}
,解决方法是不要\}
在你的面具中使用。
好的,我提供了一个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 函数会有所改进,使编写起来更容易,但我认为这种递归方法现在很好。
有趣的问题......我也在想同样的......如何构建一个字符串而不必在数字之间的某些单个部分中截断长句。
而且因为我不想创建 VBA 函数(这会更聪明),所以这是我的解决方案......
SUBSTITUTE(P253;O252;"A1A";1)
在哪里
依此类推...(即使不是我需要)如果其他值...
=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(P253;O251;"A1A";1);O252;"A2A";1);O253;"A2A";1)
好吧,我想,即使在#C 中,sprintf(....%s, %s, %d..) 也应该有多重替换原语函数。