举个例子,假设我有字符串:
FILES=APPLE=A PHOTO=P APPALE=APP NUMBER=N APPALE=APPL APPALE=APPLE LARGE=L PHOTO=PHO
我想要得到的是以下字符串:
FILES=NUMBER=N APPALE=APPLE LARGE=L PHOTO=PHO
我尝试过使用过滤器,但似乎没有一个提供很好的解决方案。
define uniq
$(eval _set :=)\
$(strip $(foreach w,$(1), $(eval _first := $(word 1,$(subst $(2),$(space),$(w))))\
$(if $(filter $(_set ),$(_first)),$(w),\
$(eval _set += $(_first)))))\
$(eval _set :=)\
$(eval _first:=)
endef
解决方案如下:
# $1 values, $2 results
# expands to results
sift = $(strip $(if $1,\
$(call sift,$(wordlist 2,$(words $1),$1),\
$(strip $(if $(filter $(firstword $1)%,$2),$2,\
$(foreach x,$2,$(if $(filter $x%,$(firstword $1)),,$x)) \
$(firstword $1)))),\
$2))
FILES = APPLE=A PHOTO=P APPALE=APPLE NUMBER=N APPALE=APPL APPALE=APP LARGE=L PHOTO=PHO
RESULTS = $(call sift,$(FILES))
all:;@echo '$(RESULTS)'
和:
$ make
APPLE=A APPALE=APPLE NUMBER=N LARGE=L PHOTO=PHO
使用 make 函数的关键是,如果你考虑递归而不是循环,它会容易得多。
我应该指出,这并不关心单词的结构;而是关心单词的结构。也就是说,这里并没有特别对待
=
。这只是另一个字母,例如 a
或 b
。
include gmtt/gmtt.mk
TEXT := FILES=APPLE=1 PHOTO=10 APPALE=A NUMBER=3 APPALE=240 APPALE=160 LARGE=false PHOTO=true
compile-vars = $(eval $(subst $(space),$(newline),$(patsubst %,****%,$(1))))$(foreach v,$(filter ****%,$(.VARIABLES)),$(patsubst ****%,%,$(v))=$($(v)))$(foreach v,$(filter ****%,$(.VARIABLES)),$(eval undefine $(v)))
$(info $(TEXT))
COMPILED := $(call compile-vars,$(TEXT))
$(info $(COMPILED))
我们滥用
make
本身内部的变量存储来执行覆盖赋值。但请注意,变量的顺序不会保留,FILES
可能会出现在列表的最后。
gmtt 只适用于
space
和 newline
。