Rewrite and Match

Introducing REWRITE and SEARCH

REWRITE allows you to do sophisticated rewriting of blocks and strings.

SEARCH performs a recursive search on data using a pattern defined by a Parse rule.

Search was originally named MATCH by Gabriele when he wrote it. I'm now calling it Search for two reasons:

Rewrite

You give rewrite a series to rewrite and a set of rewriting rules - each rule being a pair of search and replace patterns. Rewrite repeatedly applies these rules until no futher matches are found. This behaviour is very useful for changing the structure of blocks.

Here's a contrived example. Using block defined as:

block: [

    level 1 [
        level 1 + 1
    ]
    level 2 [
        level 2 + 1 [
            level 10 + 1
        ]
    ]
    level 3 [
        level 3 + 1 [myword "now"]
    ]

]

Then using the Rewrite function:

rewrite block [

    [x: integer! '+ integer!] [(rejoin [x/1 "-" x/3])] ; First rewrite pair (search/replace)

    ['myword set text string!] [a-word (to word! text)] ; Second rewrite pair (search/replace)

]

The result is:

[
    level 1 [
        level "1-1"
    ]
    level 2 [
        level "2-1" [
            level "10-1"
        ]
    ]
    level 3 [
        level "3-1" [a-word now]
    ]
]

What is important here is to recognise how the overall structure of the block has been maintained while specific patterns within it have been replaced.

Let say I wanted the block following integer levels to be transformed into paren! - I could use the following:

rewrite block [

    ['level x: integer! block!][
        'level (x/1) (to paren! x/2)
    ]

]

Which yields:

[
    'level 1 (
        level "1-1"
    )
    'level 2 (
        level "2-1" [
            level "10-1"
        ]
    )
    'level 3 (
        level "3-1" [a-word now]
    )
]

Notice here:

Keep in mind

When using rewrite there's a few points to remember:

rewrite block [
    debug ['x] [y]
    ['a] [b]
]

The script

I have modified the script to support both REBOL 3 and REBOL 2. Find it here: rewrite.r

What I've used it for:

A parse only version

For interest I've written a function that implements rewrite within a parse rule. Find it here Parse Kit.

Search

Search matches a pattern defined by a parse rule and will recursively search blocks.

Search is used internally by Rewrite. Search will:

Make sure your pattern consumes some input or you'll get an infinite loop.

Examples:

>> search {the quick brown fox} [ {brown} | {grey} ]
== "brown fox"

>> search/all {the quick brown fox} [ p: #" " (?? p)]
p: " quick brown fox"
p: " brown fox"
p: " fox"
== "fox"

I've used search in conjuction with Gabriele's Santilli's load-html (from powermezz) to do a little ad-hoc web scraping for a personal project.

Origin of REWRITE and SEARCH

Gabriele Santilli wrote rewrite.r in 2006. His original documentation on it is here and should be read: Structure matching and rewriting engine. His original script is here: rewrite.r.