Re: Multiple successive "patsubst"s…
Eric Blake <[email protected]> Wed, 19 Sep 2018 09:22:09 -0500
| Newsgroups | gmane.comp.gnu.m4.general |
|---|---|
| Organization | Red Hat, Inc. |
| Message-ID | <[email protected]> |
On 9/18/18 6:26 PM, Grant Taylor wrote: > I need some help with multiple successive "patsubst" statements. > > I have a string of text like "Grant Taylor's Blog (:test:)" (accessible > to a macro as $2) that I need to escape spaces, apostrophes, colons, and > parenthesis. I need the output of the above string to be "Grant\ > Taylor\'s\ Blog\ \(\:test\:\)". What changequote() settings are you using? That particular string is awkward with the default `' quoting (since it contains ' itself, and since you want to modify ' into \'). Note that your choice of changequote needs to be made early, before defining other macros, as the operation of user-defined macros depends heavily on the quoting in effect. > > I can get patsubst to replace one or more occurrences of any single > character. But I can't seem to get things correct to replace (escape) > multiple different characters. > > I have looked at the documentation of translit and think that it would > handle multiple characters, but I don't see how to add the leading > forward slash to escape said characters. Here's an example, without the problematic ' and with the default `' quoting characters: patsubst(``Grant Taylors Blog (:test:)'', `\([ :()]\)', `\\\1') Grant\ Taylors\ Blog\ \(\:test\:\) Wrapping that in a macro: define(`escape', `patsubst(``$1'', `\([ :()]\)', `\\\1')')dnl escape(`Grant Taylors Blog (:test:)') Grant\ Taylors\ Blog\ \(\:test\:\) Now with altered changequotes, so that you can also handle and escape an embedded ': changequote([[,]]) define([[escape]],[[patsubst([[[[$1]]]], [[\([ :()']\)]], [[\\\1]])]]) escape([[Grant Taylor's Blog (:test:)]]) Grant\ Taylor\'s\ Blog\ \(\:test\:\) > > I think I could do what I want to do with the following regular > expression in sed. But I want to do this in m4, for various reasons. > > s/\([ :()]\)/\1/g Actually, in sed, it would be: s/\([ :()']\)/\\\1/g It may also be easier to help debug if you paste what you've tried. Note that one-character quotes that might occur imbalanced in your text are inherently difficult to manage correctly through pattern substitutions; using a two-character quote delimiter that is unlikely to appear in any of the text you are processing can make life much easier (I chose [[ and ]]). -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org