ST0
ST0

Reputation: 317

String substitution in a for loop in GNU make

Assuming there are lists xl and yl with the same number of items, and an existing string s. I want to susbtitute xl's items with yl's items in s. That is, for each x in xl, I want to call $(subst x,y,$(s)) where y is the corresponding item in yl. I tried doing things like:

ns := $(shell seq $(words $(xl)))
t := $(foreach i,$(ns),$(subst $(word $(i),$(xl)),$(word $(i),$(yl)),$(s))

but this does not work because foreach expands s every iteration leading to repetitions in t.

What's a good way to get the result I want? Thank you.

Upvotes: 1

Views: 687

Answers (3)

Vroomfondel
Vroomfondel

Reputation: 2898

Just a recursive function if I understand you correctly:

multi-subst = $(if $1,$(call multi-subst,$(wordlist 2,10000,$1),$(wordlist 2,10000,$2),$(subst $(firstword $1),$(firstword $2),$3)),$3)

s = abc dca acacd 
xl = a c
yl = 1 3
s_new := $(call multi-subst,$(xl),$(yl),$(s))

It is not possible to replace substrings containing spaces of course. For more functions on strings and list you may want to take a look at gmtt

Upvotes: 1

urznow
urznow

Reputation: 1836

Using a recursive macro to generate a number sequence and evaĺ to make the text substitution, for GNU make 4.2.1:

s   := ABC def GHI bedeft ghi JKL xyz fnops
xl  := abc def ghi nop
yl  := jkl mno pqr (NOP)

# List natural numbers from 1 to length (< 1bn) of list in $1, void if $1 empty
seqn = $(strip $(if $(strip $1),$(call seqn,$(wordlist 2,999999999,$1)) $(words $1),))

ns := $(call seqn,$(patsubst %,x,$(xl)))
t := $(s)
$(foreach i,$(ns),\
    $(eval t:= $$(subst $(word $(i),$(xl)),$(word $(i),$(yl)),$$(t))))

.PHONY: all
all : ; $(foreach v,ns s t,$(info $(v): [$($(v))]))

Output from make --silent:

ns: [1 2 3 4]
s: [ABC def GHI bedeft ghi JKL xyz fnops]
t: [ABC mno GHI bemnot pqr JKL xyz f(NOP)s]

EDIT

  • foreach should loop on indices of replacement list, not target string
  • call seqn macro with $(patsubst %,x,list) for speed
  • only $(subst …) and $(t) need escaping with $$ in eval stmt

Upvotes: 1

MadScientist
MadScientist

Reputation: 101131

You'll have to operate on each word of s separately, I think.

Something like:

t := $(foreach w,$(s),$(foreach i,$(ns),$(subst $(word $i,$(xl)),$(word $i,$(yl)),$w)))

Upvotes: 0

Related Questions