是否可以在YAML中进行字符串替换?

时间:2015-05-23 00:01:25

标签: yaml

有没有办法在YAML中替换字符串。例如,我想定义- (void)timerFired:(NSTimer *)timer { seconds++; [self someCommonMethod:timer]; condition++; } - (void)someCommonMethod:(id)param { if (condition == 0) [self drawFoo]; if (condition == 1) [self drawBoo]; if (condition == 2) [self drawYoo]; } - (IBAction)reStart:(id)sender { condition = 0; [self someCommonMethod:someParamForConditions]; } 一次并在整个YAML文件中使用它。

sub

1 个答案:

答案 0 :(得分:12)

你无法在YAML中真正替换字符串值,就像用另一个子串¹替换某个字符串的子串一样。但是,YAML可以标记一个节点(在您的情况下,列表['a','b','c']带有anchor,并将其重新用作alias node

锚点采用&some_id形式,并在*some_id(而不是节点)指定节点和别名节点之前插入。

这与字符串级别的替换不同,因为在解析YAML文件期间,可以保留引用。就像在Python中加载YAML以获取集合类型上的任何锚点一样(例如,当在标量上使用锚点时):

import sys
import ruamel.yaml as yaml

yaml_str = """\
sub: &sub0 [a, b, c]
command:
    params:
        cmd1:
            type: string
            # Get the list defined in 'sub'
            enum : *sub0
            description: Exclude commands from the test list.
        cmd2:
            type: string
            # Get the list defined in 'sub'
            enum: *sub0
"""

data1 = yaml.load(yaml_str, Loader=yaml.RoundTripLoader)

# the loaded elements point to the same list
assert data1['sub'] is data1['command']['params']['cmd1']['enum']

# change in cmd2
data1['command']['params']['cmd2']['enum'][3] = 'X'


yaml.dump(data1, sys.stdout, Dumper=yaml.RoundTripDumper, indent=4)

这将输出:

sub: &sub0 [a, X, c]
command:
    params:
        cmd1:
            type: string
            # Get the list defined in 'sub'
            enum: *sub0
            description: Exclude commands from the test list.
        cmd2:
            type: string
            # Get the list defined in 'sub'
            enum: *sub0

请注意原始主播名称保留在ruamel.yaml

如果您不想在输出中使用锚点和别名,则可以覆盖ignore_aliases RoundTripRepresenter子类中的RoundTripDumper方法(该方法需要两个参数,但使用{ {1}}你不必知道这一点):

lambda *args: ....

给出了:

dumper = yaml.RoundTripDumper
dumper.ignore_aliases = lambda *args : True
yaml.dump(data1, sys.stdout, Dumper=dumper, indent=4)

这个技巧可以用来读取YAML文件,好像你已经完成了字符串替换,重新读取你转储的材料而忽略了别名:

sub: [a, X, c]
command:
    params:
        cmd1:
            type: string
            # Get the list defined in 'sub'
            enum: [a, X, c]
            description: Exclude commands from the test list.
        cmd2:
            type: string
            # Get the list defined in 'sub'
            enum: [a, X, c]

现在只有一个data2 = yaml.load(yaml.dump(yaml.load(yaml_str, Loader=yaml.RoundTripLoader), Dumper=dumper, indent=4), Loader=yaml.RoundTripLoader) # these are lists with the same value assert data2['sub'] == data2['command']['params']['cmd1']['enum'] # but the loaded elements do not point to the same list assert data2['sub'] is not data2['command']['params']['cmd1']['enum'] data2['command']['params']['cmd2']['enum'][5] = 'X' yaml.dump(data2, sys.stdout, Dumper=yaml.RoundTripDumper, indent=4) 更改为'b'

'X'

如上所述,只有在集合类型上使用锚点/别名时才需要这样做,而不是在标量上使用它时。

¹由于YAML可以创建对象,因此可能会产生影响   解析器是否创建了这些对象。 This answer描述了如何做到这一点。
²保留名称最初不可用,但是在ruamel.yaml的更新中实现