[英]Generic Template String like in Python in Dart
在python中,我经常使用字符串作为模板,例如
templateUrl = '{host}/api/v3/{container}/{resourceid}'
params = {'host': 'www.api.com', 'container': 'books', 'resourceid': 10}
api.get(templateUrl.format(**params))
这允许简单的基类设置等。 我怎样才能在飞镖中做同样的事情?
我假设我需要创建一个实用函数来解析模板并手动替换,但真的希望有一些东西可以使用。
可能是具有format
方法的 TemplateString 类,该方法采用名称/值对的Map
来替换字符串。
注意:目标是有一个通用的“格式”或“插值”功能,不需要提前知道模板中将存在哪些标签或名称。
进一步说明:模板本身在设置时并未解析。 具体来说,模板在代码中的一处定义,然后在许多其他地方使用。
Dart 没有通用的模板字符串功能,它允许您在运行时将值插入到模板中。
Dart 只允许您使用字符串中的$
语法插入带有变量的字符串,例如var string = '$domain/api/v3/${actions.get}'
。 您需要事先在代码中定义所有变量。
但是,您可以轻松创建自己的实现。
您自己在问题中解释了如何做到这一点:您传递一个映射并使用它来使用[]
运算符对参数进行通用访问。
要将模板字符串转换为易于访问的内容,我只需创建另一个包含固定组件的List
,例如/api/v3/
和另一个包含通用组件及其名称和在模板字符串中的位置的Map
。
class TemplateString {
final List<String> fixedComponents;
final Map<int, String> genericComponents;
int totalComponents;
TemplateString(String template)
: fixedComponents = <String>[],
genericComponents = <int, String>{},
totalComponents = 0 {
final List<String> components = template.split('{');
for (String component in components) {
if (component == '') continue; // If the template starts with "{", skip the first element.
final split = component.split('}');
if (split.length != 1) {
// The condition allows for template strings without parameters.
genericComponents[totalComponents] = split.first;
totalComponents++;
}
if (split.last != '') {
fixedComponents.add(split.last);
totalComponents++;
}
}
}
String format(Map<String, dynamic> params) {
String result = '';
int fixedComponent = 0;
for (int i = 0; i < totalComponents; i++) {
if (genericComponents.containsKey(i)) {
result += '${params[genericComponents[i]]}';
continue;
}
result += fixedComponents[fixedComponent++];
}
return result;
}
}
这是一个示例用法,我希望结果是您所期望的:
main() {
final templateUrl = TemplateString('{host}/api/v3/{container}/{resourceid}');
final params = <String, dynamic>{'host': 'www.api.com', 'container': 'books', 'resourceid': 10};
print(templateUrl.format(params)); // www.api.com/api/v3/books/10
}
这是一个要点。
这是我的解决方案:
extension StringFormating on String {
String format(List<String> values) {
int index = 0;
return replaceAllMapped(new RegExp(r'{.*?}'), (_) {
final value = values[index];
index++;
return value;
});
}
String formatWithMap(Map<String, String> mappedValues) {
return replaceAllMapped(new RegExp(r'{(.*?)}'), (match) {
final mapped = mappedValues[match[1]];
if (mapped == null)
throw ArgumentError(
'$mappedValues does not contain the key "${match[1]}"');
return mapped;
});
}
}
这为您提供了与 python 提供的功能非常相似的功能:
"Test {} with {}!".format(["it", "foo"]);
"Test {a} with {b}!".formatWithMap({"a": "it", "b": "foo"})
都返回“用 foo 测试它!”
在 Dart 中更容易。 下面的示例代码:
String host = "www.api.com"
String container = "books"
int resourceId = 10
String templateUrl = "$host/api/v3/$container/${resourceId.toString()}"
使用地图,您可以执行以下操作:
Map<String, String> params = {'host': 'www.api.com', 'container': 'books', 'resourceid': 10}
String templateUrl = "${params['host']}/api/v3/${params['container']}/${params['resourceId']}"
注意:上面的代码将 Map 定义为<String, String>
。 您可能需要<String, Dynamic>
(并使用.toString()
)
让它成为一个带有命名参数的函数不是最简单的吗? 如果您愿意,可以添加一些输入验证。
String templateUrl({String host = "", String container = "", int resourceid = 0 }) {
return "$host/api/v3/$container/$resourceId";
}
void main() {
api.get(templateUrl(host:"www.api.com", container:"books", resourceid:10));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.