开始

今天,我在使用自定义的配置文件语法时又发现了不足,那就是需要一种插值语法,可以减少很多重复。

比如,我有很多个字段都是http网址:

能不能不打这么多?答案是可以的,所以我设计了新语法————函数。

它类似ahk的api之Format,但是只有插值{}语法。

实现

在这里,我只给出它的一个demo,完成字符串的信息提取与动态的插值。

1. 语法

它的语法很简单,看下面的例子:

&fn(a, b) : http://{a}:{b}

vm : $fn(192.168.6.100, 8080)$

2. 解析

实际上,我们要关心的只有方法参数,与后面的方法体,即:

  • (a, b)
  • http://{a}:{b}

要做的是实现参数与方法体内变量位置的映射,比如上面的例子就是:

{
	1 : 1  ; 方法体内第一个变量对应第一个参数
	2 : 2  ; 同上
}
  • 先从参数开始,我们要提取出参数名和对应的顺序:
def := '(a, b)'
def := StrReplace(def, A_Space)
if def[1] != '(' or def[-1] != ')'
  MsgBox 'err'
def := def.substring(2, def.Length)
params := {}
StrSplit(def, ',').filter(v => v).foreach((v, i) => params[v] := i)

; MToString params
; => {a : 1, b : 2}
  • 然后是方法体,需要提取出变量位置与还原出去除变量后的字符串:

body := 'http://{b}:{a}'

_pos := 1, idx := {}, post := ''
for i, v in body {
  if v = '{' {
    _pos := i
  } else if v = '}' {
    idx[idx.Length + 1] := body.substring(_pos + 1, i)
    post := SubStr(post, 1, post.Length - i + _pos + 1)
  }
  post .= v
}

; MsgBox post
; => http://{}:{}
; MToString idx
; => { 1 : b, 2 : a}
  • 第三步,建立映射关系

for k, v in idx.OwnProps() {
  idx[k] := params[v]
}

; MToString idx
; => { 1 : 2, 2 : 1}
  • 第四步,实现动态插值

这一步需要对ahk的语法十分了解。

__f__ := (_p*) => __f.Bind(post, idx, _p*)

MsgBox __f__(1, 2)()

__f(str, mapping, p*) {
  i := 1, _chs := str.toChararray(), _r := '', _c := 1
  while i + 1 <= _chs.Length {
    if _chs[i] = '{' and _chs[i + 1] = '}' {
      _r .= p[mapping[_c]], _c++, i++
    } else _r .= _chs[i]
    i++
  }
  return _r
}

最后,打印的结果就是:http://2:1

对应到配置文件语法就是下面这样:

; vm : $fn(2, 1)$
a := 2, b := 1
MsgBox __f__(a, b)()
posted on 2024-08-05 19:03  落寞的雪  阅读(146)  评论(0)    收藏  举报