繁体   English   中英

Dart 中的 Python 中的通用模板字符串

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM