Expanding and Compressing Tabs
Problem
aligned with tab stops.For example, you want to display formatted text to users in a
standardized way.
Solution
Example Switching tabs and spaces$rows = $db->query('SELECT message FROM messages WHERE id = 1'); $obj = $rows->fetch(PDO::FETCH_OBJ);
$tabbed = str_replace(' ' , "\t", $obj->message);
$spaced = str_replace("\t", ' ' , $obj->message);
print "With Tabs: <pre>$tabbed</pre>";
print "With Spaces: <pre>$spaced</pre>"
;
Using str_replace() for conversion, however, doesn’t respect tab stops. If you want
tab stops every eight characters, a line beginning with a five-letter word and a tab should
have that tab replaced with three spaces, not one.
Example tab_expand( )
function tab_expand($text) {
while (strstr($text,"\t")) {
$text = preg_replace_callback('/^([^\t\n]*)(\t+)/m',
'tab_expand_helper', $text);
}
return $text;
}
function tab_expand_helper($matches) {
$tab_stop = 8;
return $matches[1] .
str_repeat(' ',strlen($matches[2]) *
$tab_stop - (strlen($matches[1]) % $tab_stop));
}
$spaced = tab_expand($obj->message);
Example tab_unexpand( )
function tab_unexpand($text) {
$tab_stop = 8;
$lines = explode("\n",$text);
foreach ($lines as $i => $line) {
// Expand any tabs to spaces
$line = tab_expand($line);
$chunks = str_split($line, $tab_stop);
$chunkCount = count($chunks);
// Scan all but the last chunk
for ($j = 0; $j < $chunkCount - 1; $j++) {
$chunks[$j] = preg_replace('/ {2,}$/',"\t",$chunks[$j]);
}
// If the last chunk is a tab-stop's worth of spaces
// convert it to a tab; Otherwise, leave it alone
if ($chunks[$chunkCount-1] == str_repeat(' ', $tab_stop)) {
$chunks[$chunkCount-1] = "\t";
}
// Recombine the chunks
$lines[$i] = implode('',$chunks);
}
// Recombine the lines
return implode("\n",$lines);
}
$tabbed = tab_unexpand($obj->message);
Both functions take a string as an argument and return the string appropriately modi‐
fied.
Discussion
Each function assumes tab stops are every eight spaces, but that can be modified by
changing the setting of the $tab_stop variable.
The regular expression in tab_expand() matches both a group of tabs and all the text
in a line before that group of tabs. It needs to match the text before the tabs because the
length of that text affects how many spaces the tabs should be replaced with so that
subsequent text is aligned with the next tab stop. The function doesn’t just replace each
tab with eight spaces; it adjusts text after tabs to line up with tab stops.
Similarly, tab_unexpand() doesn’t just look for eight consecutive spaces and then re‐
place them with one tab character. It divides up each line into eight-character chunks
and then substitutes ending whitespace in those chunks (at least two spaces) with tabs.
This not only preserves text alignment with tab stops; it also saves space in the string.
No comments:
Post a Comment