% !Mode:: "TeX:UTF-8:Main" %needs a fontloader 2017-07-28 or later %substitutions at word boundaries \documentclass{article} \usepackage{luacode,fontspec} \begin{luacode*} fonts.handlers.otf.addfeature { name = "test-a", type = "chainsubstitution", lookups = { { type = "substitution", data = { ["a"] = "A", ["b"] = "B", ["c"] = "C", ["d"] = "D", }, }, { type = "ligature", data = { ['1'] = { "a", "b" }, ['2'] = { "c", "d" }, }, }, }, data = { rules = { { before = { { " ", 0xFFFC } }, current = { { "a" }, { "b" } }, lookups = { 2 }, }, { current = { { "c" }, { "d" } }, after = { { 0xFFFC, " " } }, lookups = { 2 }, }, { current = { { "a" } }, after = { { "b" } }, lookups = { 1 }, }, { current = { { "c" } }, after = { { "d" } }, lookups = { 1 }, }, }, }, } fonts.handlers.otf.addfeature { name = "test-b", type = "chainsubstitution", lookups = { { type = "ligature", data = { ['1'] = { "a", "b" }, ['2'] = { "c", "d" }, }, }, }, data = { rules = { { -- the space is redundant as 0xFFFC contains it before = { { " ", 0xFFFC } }, current = { { "a" }, { "b" } }, lookups = { 1 }, }, { current = { { "c" }, { "d" } }, -- the space is redundant as 0xFFFC contains it after = { { 0xFFFC, " " } }, lookups = { 1 }, }, }, }, } fonts.handlers.otf.addfeature { name = "test-c", type = "chainsubstitution", lookups = { { type = "ligature", data = { ['1'] = { "a", "b" }, ['2'] = { "c", "d" }, }, }, }, data = { rules = { { before = { { " " } }, current = { { "a" }, { "b" } }, lookups = { 1 }, }, { current = { { "c" }, { "d" } }, after = { { " " } }, lookups = { 1 }, }, }, }, } \end{luacode*} \setmainfont{Arial}[RawFeature=+test-a;] \begin{document} Substitutions at word boundaries (spaces): ab ab abxcd abxcdcdcd expected output: 1 1 1x2 1xCdCd2 \end{document}