# How to do substitions (like perl s/// operator) in rewrites?

**URL:** <https://www.ruby-forum.com/t/how-to-do-substitions-like-perl-s-operator-in-rewrites/181352>\
**Category:** NGINX\
**Created:** [January 10, 2010, 3:09pm UTC](https://www.ruby-forum.com/t/how-to-do-substitions-like-perl-s-operator-in-rewrites/181352 "2010-01-10T15:09:28Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![bartschipper](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/e47774/32.png) [@bartschipper](https://www.ruby-forum.com/u/bartschipper)\
**Post date:** [January 10, 2010, 3:09pm UTC](https://www.ruby-forum.com/t/how-to-do-substitions-like-perl-s-operator-in-rewrites/181352/1 "2010-01-10T15:09:28Z")

</div>

I recently migrated a web site from Apache to Nginx (and from CMS-system  
x to CMS system y)  
Almost all of the rewrites are OK in the new CMS, except for one older  
class of article URLs:  
[http://example.com/News/Articlepage-News/This-is-the-best-News-EVER.htm](http://example.com/News/Articlepage-News/This-is-the-best-News-EVER.htm)  
(example)

The direct mapping for these literal urls to the new urls is lost.  
I do however have a file (200k+ entries) that maps the titles to  
article-id’s like so:

# old-class-urls.txt: (first two commented lines are not actually in the

file)

# all lowercase title without spaces and hyphens article-id

thisisthebestnewsever 123456;  
…

In apache I used a rewritemap to rewrite these urls:

# httpd.conf:

…  
RewriteMap articles prg:/etc/httpd/rewrites/old-class-article-urls.pl  
…

# old-class-article-urls.pl:

#!/usr/bin/perl

$| = 1;

###############################################

# code to be executed at startup of webserver

###############################################

open(TEXTFILE,";  
close TEXTFILE;

foreach $line (@lines) { # load the  
data in an associative array for fast lookup  
($keyword,$article\_id) = split(/\s+/,$line);  
$keys{$keyword} = $article\_id;  
}

##########################################

# code to be once every URL is requested

##########################################

while () {  
$url = $\_;  
chomp($url);  
if($url =~ //([^/]+).htm$/) { # a match  
could be made  
$keyword = lc($1);  
$keyword =~ s/-//g;  
if($keys{$keyword}) {  
print ‘old-class-url.php?articleid=’ . $keys{$keyword}.“\n”;  
next;  
}  
}  
print “Not found\n”; # no match  
could be made  
}

I was hoping something similar or even easier could be done with Nginx:

map $uri $old-class-url {  
include /etc/nginx/rewrites/old-class-urls.txt;  
}  
…  
server {  
…  
location ~\* ^/News/Articlepage-News/._htm {  
rewrite ^/News/Articlepage-News/(._)htm $1 ;

### 

### change $uri to lowercase and remove the hyphens…

### I am looking for something equivalent like in perl:

### s/-//g;

### s/.\*/\L{$1}/;

### 

```
    if ($old-class-url) {
            rewrite ^ 

```

/old-class-url.php?articleid=$old-class-url permanent;  
}  
}  
}

I have seen questions about similar functionality in the forums, but not  
with a solution:

> **[Changing case of URLs](https://forum.nginx.org/read.php?2,34788)**
>
> Hi, Does nginx have a function/map like Apache's "int:tolower" that can be used to rewrite something like "/SuperUser/file.txt" to "/superuser/file.txt"? Regards, Dennis \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

> **[Change underscore to hyphen urls](https://forum.nginx.org/read.php?9,2511)**
>
> Hello, I'm switching to nginx from apache. With the move i have also updated the blog engine. My blog url used to be: domain.com/blog/this\_is\_the\_entry.html and now it is: domain2.com/this-is-the-entry.html How

Is it possible to solve this issue this way or do you recommend a  
different solution?

Thanks in advance,  
Bart

Posted at Nginx Forum:

> **[How to do substitions (like perl s/// operator) in rewrites?](https://forum.nginx.org/read.php?2,39425,39425#msg-39425)**
>
> I recently migrated a web site from Apache to Nginx (and from CMS-system x to CMS system y) Almost all of the rewrites are OK in the new CMS, except for one older class of article URLs:...

---

<div class="post-metadata">

**Author:** ![bartschipper](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/e47774/32.png) [@bartschipper](https://www.ruby-forum.com/u/bartschipper)\
**Post date:** [January 10, 2010, 6:10pm UTC](https://www.ruby-forum.com/t/how-to-do-substitions-like-perl-s-operator-in-rewrites/181352/2 "2010-01-10T18:10:19Z")

</div>

hi

the map module is case insensitive, it uses ngx\_hash\_strlow to produce  
the key internally so this is not a problem

for the hypens problem i would generate a map file with two keys for  
each article id, one with and one without hyphens like:

title-1 1  
title1 1

cheers, bernd

Posted at Nginx Forum:

> **[Re: How to do substitions (like perl s/// operator) in rewrites?](https://forum.nginx.org/read.php?2,39425,39472#msg-39472)**
>
> I recently migrated a web site from Apache to Nginx (and from CMS-system x to CMS system y) Almost all of the rewrites are OK in the new CMS, except for one older class of article URLs:...

---

<div class="post-metadata">

**Author:** ![bartschipper](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/e47774/32.png) [@bartschipper](https://www.ruby-forum.com/u/bartschipper)\
**Post date:** [January 10, 2010, 3:28pm UTC](https://www.ruby-forum.com/t/how-to-do-substitions-like-perl-s-operator-in-rewrites/181352/3 "2010-01-10T15:28:12Z")

</div>

Hello!

On Sun, Jan 10, 2010 at 09:08:48AM -0500, bartschipper wrote:

> …  
> […]

> ### I am looking for something equivalent like in perl:
> 
> ### s/-//g;
> 
> ### s/.\*/\L{$1}/;

There is no easy way to do this without perl as of now. With  
embedded perl it’s trivial though.

Maxim D.

---

<div class="post-metadata">

**Author:** ![bartschipper](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/e47774/32.png) [@bartschipper](https://www.ruby-forum.com/u/bartschipper)\
**Post date:** [January 11, 2010, 9:29am UTC](https://www.ruby-forum.com/t/how-to-do-substitions-like-perl-s-operator-in-rewrites/181352/4 "2010-01-11T09:29:07Z")

</div>

Thank you for your responses!

I think Maxim is right and embedded Perl is the way to go.

Bernd’s idea would work if there was an easy way to generate a map file  
with hyphens from the source file.  
However the source file has 200k+ entries that look like this:

thisisthebestnewsever 123456;  
expertsadvicetoeatmorefish 123457;  
…

I can not think of an automated way to convert this to:

this-is-the-best-news-ever 123456;  
thisisthebestnewsever 123456;  
experts-advice-to-eat-more-fish 123457;  
expertsadvicetoeatmorefish 123457;  
…

Knowing that the map module is case-insensitive may safe me from  
confusion in the future.

Thanks again,  
Bart

Posted at Nginx Forum:

> **[Re: How to do substitions (like perl s/// operator) in rewrites?](https://forum.nginx.org/read.php?2,39425,39666#msg-39666)**
>
> I recently migrated a web site from Apache to Nginx (and from CMS-system x to CMS system y) Almost all of the rewrites are OK in the new CMS, except for one older class of article URLs:...

---

<div class="post-metadata">

**Author:** ![bartschipper](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/e47774/32.png) [@bartschipper](https://www.ruby-forum.com/u/bartschipper)\
**Post date:** [January 11, 2010, 10:18pm UTC](https://www.ruby-forum.com/t/how-to-do-substitions-like-perl-s-operator-in-rewrites/181352/5 "2010-01-11T22:18:57Z")

</div>

Issue solved!

I followed Maxim’s advice and compiled embedded perl in. However, I  
found the configuration not as trivial as Maxim claimed: embedded perl  
documentation is scarce and examples are rare.

The following configuration solved it for me and it may serve as an  
example for others of using the map module together with embedded perl:

http {  
…

# use the map module to include a list with keys and corresponding

article-ids  
map $uri $old-class-url {  
include /etc/nginx/rewrites/old-class-urls.txt; # (see the first  
post for a sample of the contents)  
}

# lower case uri’s file name part and remove dashes with perl. Return

result to nginx variable $old\_uri  
perl\_set $old\_uri ‘sub {  
my $r = shift;  
my $uri = $r-\>uri;  
if($uri =~ //([^/]+).htm$/) {  
$uri = lc($1);  
$uri =~ s/-//g;  
}  
return $uri;  
}’;  
…  
server {  
…  
location ~\* ^/News/Articlepage-News/.\*htm$ {

# rewrite $uri to variable $old\_uri

```
  rewrite ^ $old_uri ;

```

# return the article-id in the rewrite if $uri appears in the map

```
  if ($old-class-url) {
    rewrite ^ /old-class-url.php?articleid=$old-class-url 

```

permanent;  
}  
}  
…  
}  
}

I welcome any suggestion for a simpler solution.

Bart Schipper

Posted at Nginx Forum:  
[http://forum.nginx.org/read.php?2,39425,39944#msg-39944](http://forum.nginx.org/read.php?2,39425,39944#msg-39944)
