[Top][All Lists]

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

Re: Multiple successive "patsubst"s…

From: Grant Taylor
Subject: Re: Multiple successive "patsubst"s…
Date: Wed, 19 Sep 2018 09:54:41 -0600
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.6.0

Thank you for your help Eric.  That's what I needed.

On 09/19/2018 08:22 AM, Eric Blake wrote:
What changequote() settings are you using?

I changed quotes (my first time ever in m4) while working on this. I now have:

changequote(`[', `]')

The patsubst now looks like this:

patsubst([$1], [ ], [\\ ])

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 changed quotes at the start of my file and updated all subsequent lines accordingly.

Here's an example, without the problematic ' and with the default `' quoting characters:

patsubst(``Grant Taylors Blog (:test:)'', `\([ :()]\)', `\\\1')
Grant\ Taylors\ Blog\ \(\:test\:\)

How did I miss both the range […] and back references \(…\). I guess I thought patsubst(…) was simple replacement, particularly considering that regexp(…) is a separate macro.

That is definitely an improvement. (I just commented out the copy using changed quotes, uncommented and adjusted original version.)

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 just tried the following, based on your recommendation, and seems to do what I want. Or at least I need to do more analysis and see if it does or does not correctly modify the data the way that I want.

changequote(`{', `}')
patsubst({$1}, {\([' :()]\)}, {\\\1})

Actually, in sed, it would be:

s/\([ :()']\)/\\\1/g

O.o? I'd swear that I tested (command line didn't work (b/c of quoting), but sed file did). But it's somewhat moot as it got the point across and you were able to provide the help with patsubst that I needed.

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;

Fortunately (for me) this particular project doesn't care about imbalanced quotes in the input text. In fact, there will purposefully be imbalanced quotes in the incoming text. Most frequently the apostrophe used to mark possession, "Grant's Blog", type thing.

Nor do I expect to have anything unbalanced in my m4 code.

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 ]]).

Fair enough. I had used "[" and "]" for a while yesterday afternoon. This morning I've switched to "{" and "}" and things seem to be working as I want them to.

Here's a (sanitized) copy of the core of the code that I'm working on.

changequote(`{', `}')
define({rss}, {# $1
:0 E
* for <ifelse(index({$2}, address@hidden), {-1}, {translit({patsubst({$1}, { }, {})}, {A-Z}, {a-z})@r{}ss.example.com}, {$2})>;
.maildir/.RSS.patsubst({$1}, {\([' :()]\)}, {\\\1})/

The purpose of the code is to be able to successively call the rss macro to build Procmail recipes. — Ultimately I'll redefine the macros to output Maildrop rules. That way I can use the same input data to generate different output.

rss(two three)
rss(four's five)
rss({six :: seven (eight)})

# one
:0 E
* for <address@hidden>;

# two three
:0 E
* for <address@hidden>;
.maildir/.RSS.two\ three/

# four's five
:0 E
* for <four'address@hidden>;
.maildir/.RSS.four\'s\ five/

# six :: seven (eight)
:0 E
* for <six::seven(eight)@rss.example.com>;
.maildir/.RSS.six\ \:\:\ seven\ \(eight\)/

The input listed above is MUCH easier to maintain and can be worked with programmatically, including sorting the lines in the input file.

Thank you again for your help Eric.  That's what I needed.  :-)

Grant. . . .
unix || die

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature

reply via email to

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