地形 | 替换字符串中的多个子字符串

Dat*_*fer 5 terraform terraform0.12+

我有一个字符串,其中有多个子字符串需要替换。

字符串: string1 = "I want to fly tomorrow"

我需要从地图上取出任何需要替换的东西。

地图:

map1 = {
    "I": "we"
    "want": "do not want"
    "tomorrow": "today"
  }
Run Code Online (Sandbox Code Playgroud)

因此,映射中的键map1是字符串中需要替换的内容string1,值应该是字符串中的新值。

结果应该是这样的: we do not want to fly today

我一直在想一个解决方案,但还差得远。

我试过这个:

try = [for replacement in keys(local.map1): replace(local.string1, replacement, local.map1[replacement])]
Run Code Online (Sandbox Code Playgroud)

但这会返回一个字符串列表,每个字符串仅替换一个值。

注意string1map1只是示例,它们可以有任何其他值,所以我正在寻找通用解决方案:)

Mar*_*cin 12

我认为你这样做是如下:

variable "string1" {
  default = "I want to fly tomorrow"
}

variable "map1" {
  default = {
    "I" = "we"
    "want" = "do not want"
    "tomorrow" = "today"
  }
}

output "test" {
  value = join(" ", [for word in split(" ", var.string1): lookup(var.map1, word, word)]) 
}
Run Code Online (Sandbox Code Playgroud)

输出是:

we do not want to fly today
Run Code Online (Sandbox Code Playgroud)

  • 用于迭代字符串并根据需要使用“查找”来替换或默认为原始元素的聪明算法。 (3认同)

all*_*ejo 11

这是工作所需要的;这是在 Terraform 0.12.23 上测试的。与 Marcin 的答案不同的是,这适用于彼此相邻、字符之间(例如引号)或不被空格分隔的占位符。

鉴于我们有一个带有格式化占位符的文件{},我需要将它们替换为键/值对的映射。

这是您可以复制/粘贴的内容。

样本.txt

Hello {name}, my favorite food is {food} I'd
  like to eat {food} and sleep.
  Here's a {non_existent} variable
Run Code Online (Sandbox Code Playgroud)

游乐场.tf

locals {
  input = file("./sample.txt")

  map = {
    food = "Sushi"
    name = "Data_sniffer"
  }

  out = join("\n", [
    for line in split("\n", local.input) :
      format(
        replace(line, "/{(${join("|", keys(local.map))})}/", "%s"),
        [
          for value in flatten(regexall("{(${join("|", keys(local.map))})}", line)) :
            lookup(local.map, value)
        ]...
      )
  ])
}

output "test_out" {
  value = local.out
}
Run Code Online (Sandbox Code Playgroud)

输出

$ terraform apply

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

test_out = Hello Data_sniffer, my favorite food is Sushi I'd
  like to eat Sushi and sleep.
  Here's a {non_existent} variable
Run Code Online (Sandbox Code Playgroud)

以下是这个魔法如何运作的解释:

  1. 第一步是按换行符分割文本,因此您将可以使用以下内容:

    Hello {name}, my favorite food is {food} I'd
      like to eat {food} and sleep.
      Here's a {non_existent} variable
    
    Run Code Online (Sandbox Code Playgroud)
  2. 现在我们要替换占位符。然而,在撰写本文时,Terraform 没有一种简单的方法可以轻松替换一个字符串中的多个字符串。所以我们会format同时使用这个函数;这需要%s它的占位符。基本上,我们希望我们的数组现在看起来像这样:

    locals {
      input = file("./sample.txt")
    
      map = {
        food = "Sushi"
        name = "Data_sniffer"
      }
    
      out = join("\n", [
        for line in split("\n", local.input) :
          format(
            replace(line, "/{(${join("|", keys(local.map))})}/", "%s"),
            [
              for value in flatten(regexall("{(${join("|", keys(local.map))})}", line)) :
                lookup(local.map, value)
            ]...
          )
      ])
    }
    
    output "test_out" {
      value = local.out
    }
    
    Run Code Online (Sandbox Code Playgroud)

    为了获得每一行的转换,我们希望将有效{}占位符替换为%s; 即我们不想替换{non_existent}地图中不存在的内容。

    我们利用 Terraform 允许您进行正则表达式替换的事实,因此我们需要以下正则表达式:({(food|name)}其中foodname是我们要替换的键)。由于我们不想手动维护此列表,因此我们使用字符串插值以编程方式构建正keys()表达式

    "/{(${join("|", keys(local.map))})}/"
    
    Run Code Online (Sandbox Code Playgroud)

    现在我们有了正则表达式,我们可以使用它replace,它支持正则表达式。

    replace(line, "/{(${join("|", keys(local.map))})}/", "%s")
    
    Run Code Online (Sandbox Code Playgroud)
  3. 可是等等!我们现在所拥有的是%s,我们如何知道以什么顺序替换什么???这就是regexall()进来的地方(不是 regex())。使用与上面几乎相同的正则表达式,我们将再次提取匹配的占位符。

    /(上面的正则表达式和这个正则表达式之间的唯一区别是开头和结尾缺少)

    regexall("{(${join("|", keys(local.map))})}", "Hello {name}, my favorite food is {food} I'd")
    
    Run Code Online (Sandbox Code Playgroud)

    此函数调用将返回所有找到的占位符。在这里使用regexall()所有内容很重要,否则它会在第一场比赛时停止。

    $ terraform apply
    
    Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
    
    Outputs:
    
    test_out = Hello Data_sniffer, my favorite food is Sushi I'd
      like to eat Sushi and sleep.
      Here's a {non_existent} variable
    
    Run Code Online (Sandbox Code Playgroud)

    我们在这里不需要双重嵌套列表,所以我们将使用flatten().

    flatten(
      regexall("{(${join("|", keys(local.map))})}", "Hello {name}, my favorite food is {food} I'd")
    )
    
    Run Code Online (Sandbox Code Playgroud)

    现在将返回,

    [
      "Hello {name}, my favorite food is {food} I'd",
      "  like to eat {food} and sleep.",
      "  Here's a {non_existent} variable"
    ]
    
    Run Code Online (Sandbox Code Playgroud)

    现在,我们可以使用列表通过函数从映射中查找相应的值lookup()

    [
      for value in flatten(regexall("{(${join("|", keys(local.map))})}", "Hello {name}, my favorite food is {food} I'd")) :
        lookup(local.map, value)
    ]
    
    Run Code Online (Sandbox Code Playgroud)

    返回:

    [
      "Data_sniffer",
      "Sushi",
    ]
    
    Run Code Online (Sandbox Code Playgroud)

    然后可以将这个替换值数组输入到我们的顶级format()调用中。但是,format()不接受数组,它需要逗号分隔的参数。因此,请使用...运算符将​​列表扩展为函数参数。