[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Multiple successive "patsubst"s…

From: Eric Blake
Subject: Re: Multiple successive "patsubst"s…
Date: Wed, 19 Sep 2018 09:22:09 -0500
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.0

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 ':

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

reply via email to

[Prev in Thread] Current Thread [Next in Thread]