Recipe 1.7. Expanding and Compressing Tabs
Author: Tom Christiansen & Nathan Torkington
Date: 1999-07-02T01:28:52Z

#

| Chapter 1 Strings |

## 1.7. Expanding and Compressing Tabs

### Problem

You want to convert tabs in a string to the appropriate number of spaces, or vice versa. Converting spaces into tabs can be used to reduce file size when the file has many consecutive spaces. Converting tabs into spaces may be required when producing output for devices that don't understand tabs or think they're at different positions than you do.

### Solution

Either use a rather funny looking substitution:

    while ($string =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {
        # spin in empty loop until substitution finally fails
    }

Or the standard Text::Tabs module:

    use Text::Tabs;
    @expanded_lines  = expand(@lines_with_tabs);
    @tabulated_lines = unexpand(@lines_without_tabs);

### Discussion

Assuming that tab stops are set every N positions (where N is customarily eight), it's easy to convert them into spaces. The standard, textbook method does not use the Text::Tabs module but suffers from being difficult to understand. Also, it uses the `$`` variable, whose very mention currently slows down every pattern match in the program. The reason for this is given in the "Special Variables" section of the Introduction to Chapter 6.

    while (<>) {
        1 while s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
        print;
    }

If you're looking at the second `while` loop and wondering why it couldn't have been written as part of a simple `s///g` instead, it's because you need to recalculate the length from the start of the line again each time (stored in `$``) rather than merely from where the last match occurred.

The obscure convention `1` `while` `CONDITION` is the same as `while` `(CONDITION)` `{` `}`, but shorter. Its origins date to when Perl ran the first incredibly faster than the second. While the second is now almost as fast, it remains convenient, and the habit has stuck.

The standard Text::Tabs module provides conversion functions to convert both directions, exports a `$tabstop` variable to control the number of spaces per tab, and does not incur the performance hit because it uses `$1` and `$2` rather than `$&` and `$``.

    use Text::Tabs;
    $tabstop = 4;
    while (<>) { print expand($_) }

We can also use Text::Tabs to "unexpand" the tabs. This example uses the default `$tabstop` value of 8:

    use Text::Tabs;
    while (<>) { print unexpand($_) }

### See Also

The manpage for the Text::Tabs module (also in Chapter 7 of Programming Perl); the `s///` operator in perlre (1) and perlop (1) and the "Pattern Matching" and "Regular Expressions" sections of Chapter 2 of Programming Perl

1.6. Reversing a String by Word or Character |  | 1.8. Expanding Variables in User Input