Click here to Skip to main content
13,199,596 members (27,260 online)
Rate this:
 
Please Sign up or sign in to vote.
See more:
Your coding challenge of the week is a simple one. Or so it seems.

Given a text string, convert the tabs to spaces. Assuming tab markers are 4 characters apart

[ ][ ][tab]Hello, world!

becomes
[ ][ ][ ][ ]Hello, World!


Where [ ] = space character, [tab] = tab character (I chose to use these instead of " " and " " (or "\t") to make it easier to spot the spaces and tabs.)

Another test case is left as an exercise for the reader.
[ ][ ][ ][tab][tab][ ][tab]Hello, world!



Again: A T-shirt awarded for audacity, for style, for outrageous use of inappropriate languages. Mostly for the entry that entertains us the most.

Last week's challenge Coding challenge: bad word filter[^] was won by PIEBALDConsult under the "God I miss coding" category. Send Sean @codeprject your address and T-shirt size and a Christmas present will come your way.

What I have tried:

To remain calm, mostly.

Got a coding challenge idea? Send it to me at chris@codeproject.com.
Posted 1-Dec-16 9:46am
Updated 6-Dec-16 21:24pm
v3
Comments
Afzaal Ahmad Zeeshan 1-Dec-16 17:27pm
   
Do you mean tab spaces, or just tab as in character?
CHill60 2-Dec-16 4:45am
   
"outrageous use of inappropriate languages" ... darn it, I was going to provide a VB6 solution then remembered I destroyed the install CDs in a ritual bonfire last Samhain
Graeme_Grant 2-Dec-16 7:04am
   
Any reason you are converting words to Title Case as well???
PIEBALDconsult 2-Dec-16 8:49am
   
Been there, done that. I'll resurrect some ancient code.

And don't forget this little beauty...
https://www.codeproject.com/Articles/32593/Untabify-and-Tabify

ppolymorphe 3-Dec-16 15:28pm
   
I think some solutions will fail with:
"[ ][ ][ ][ ][ ][tab]Hello, world!"
PIEBALDconsult 3-Dec-16 17:43pm
   
And what do you think is correct?
ppolymorphe 3-Dec-16 21:32pm
   
8 leading spaces:
"[ ][ ][ ][ ][ ][ ][ ][ ]Hello, world!"
PIEBALDconsult 4-Dec-16 10:00am
   
I agree. And mine should do that.
Page 1 of 3

Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 1

Brainfuck


Well, that was fun :)
>,[>+++++++++<[>->+<<-]>[>-------------------------------->-------------------------------->]<++++++++++++++++++++++++++++++++[.--------------------------------]<++++++++++++++++++++++++++++++++.>>>,]

To run this, paste the code in this online interpreter[^], fill in your input in the "input" field and click "execute".

So what's actually going on here? Here is the code explained (while Brainfuck ignores characters that it doesn't know, the code below isn't runnable because the commentary contains some chars that are valid in Brainfuck).
>  # Jump a cell ahead. We'll need the first cell later.
,  # Find a char in the input.
[  # If there is no input, jump past the matching ]. Here that ends the program.
 
  >  # Jump another cell ahead.
  +++++++++  # Put the value 9 in this cell.
 
  <  # Jump one cell back (to our input cell).
  [>->+<<-]  # While this cell is not 0, do these things: a) decrement the value at the next cell. b) increment the value two cells ahead. c) decrement the value of our input cell
 
  # Now the cell that originally contained our input is 0, the cell ahead of that one is non-zero if the input is no tab, zero if it is a tab (I'll call this the "signal cell"), and the cell ahead of THAT one is a copy of our original input.
 
  >  # Jump to the signal cell.
  [  # If the cell is zero, jump to the matching ], otherwise continue.
    >--------------------------------  # Jump to our input copy and decrease the value by 32.
    >--------------------------------  # Jump another cell ahead and do the same. (This cell starts at 0 and won't end up at -32 but 224 because of underflow. It doesn't matter though.
    >  # Jump to the next cell, to be sure that this one is zero and we are not stuck in a loop.
  ]  # If the current cell value is zero (which it is!), just continue the program (otherwise go back to the matching [).
 
  <  # Jump back a cell. If our input was a tab, this new cell will be the cell we skipped in the beginning. If it wasn't a tab, it will be our "224 cell".
  ++++++++++++++++++++++++++++++++  # Increase by 32. In case of a tab, this will be 32, otherwise 0.
  [.--------------------------------]  # If the value is not 0 (then it must be a space), print it and make sure it only gets called once. This makes sure that a tab gets replaced with TWO spaces as the challenge requires.
 
  <  # Jump back a cell. If our input was a tab this will be 0, otherwise the original char minus 32.
  ++++++++++++++++++++++++++++++++  # Increase by 32.
  .  # Print.
 
>>>  # Jump three cells ahead, so we don't have to worry about our past cells. Here we also keep our "spare cell" in mind like in the beginning of the program.
,  # Look for a char in the input.
]  # Is it 0? No input anymore and close the program. Not 0? Go back to the first [.
  Permalink  
v2
Comments
Chris Maunder 1-Dec-16 18:28pm
   
-2 points for using the dumbest language ever. +4 points for the pain involved.
Matthew Dennis 5-Dec-16 17:23pm
   
actually probably not in the top 10 dumbest languages. Try Malbolge https://en.wikipedia.org/wiki/Malbolge. I'm not even going to attempt it.
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 3

Maybe I took things too literally.

using System;
using System.Collections.Generic;
using System.Linq;
 
namespace Test
{
    public class TabConversion
    {              
        public static void Main(string[] args)
        {
            string literalTest1 = "[ ][ ][tab]Hello, world!";
            string literalTest2 = "[ ][ ][ ][tab][tab][ ][tab]Hello, world!";
 
            DoTests(new string[] { literalTest1, literalTest2 }, "[tab]", "[ ][ ]");
            DoTests(new string[] { 
                literalTest1.Replace("[tab]", "\t").Replace("[ ]"," "), 
                literalTest2.Replace("[tab]", "\t").Replace("[ ]"," ") }, 
                "\t", "  ");
        }
 
        // This is probably the fastest way
        public static string ReplaceTabs(string text, string tabText, string spaceText)
        {
            return text.Replace(tabText, spaceText);
        }
 
        // This is a bad way, but hey, it works
        public static string ReplaceTabsBySplitting(string text, string tabText, string spaceText)
        {
            var splits = text.Split(new string[] { tabText }, StringSplitOptions.None);
            if (splits.Length > 1)
            {
                return string.Join(spaceText, splits);
            }
            else
            {
                return text;
            }
        }
 
        // What is this I don't even
        public static string ReplaceTabsByLinq(string text, string tabText, string spaceText)
        {
            List<string> t = new List<string>();
            text.Split(new string[] { tabText }, StringSplitOptions.None).ToList().ForEach(s => { t.Add(s); t.Add(tabText); });
            string result = string.Join("", t.Select<string, string="">(s => s == tabText ? spaceText : s).ToArray<string>().Reverse().Skip(1).Reverse());
            return result;
        }
 
        // Felt bad about replacing the tabs.  Tab lives matter!
        public static string UnreplaceTabs(string text, string tabText, string spaceText)
        {
            return text.Replace(spaceText, tabText);
        }
 
        // DRY
        public static void DoTests(string[] tests, string tabText, string spaceText)
        {
            foreach (string test in tests)
            {
                Console.WriteLine("-----------------------------");
                Console.WriteLine("Original\t\"" + test + "\"");
                Console.WriteLine();
                Console.WriteLine("string.Replace\t\"" + ReplaceTabs(test, tabText, spaceText) + "\"");
                Console.WriteLine("string.Split\t\"" + ReplaceTabsBySplitting(test, tabText, spaceText) + "\"");
                Console.WriteLine("Using LINQ\t\"" + ReplaceTabsByLinq(test, tabText, spaceText) + "\"");
                Console.WriteLine("Space->Tab\t\"" + UnreplaceTabs(test, tabText, spaceText) + "\"");
                Console.WriteLine();
            }
        }
    }
}


Could probably get the LINQ method to a single line, but out of time for now.
  Permalink  
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 17

Thought I'd give this a go, but alas my solution seems too sensible for this challenge... :D

Using C# enumerables and yield...
public static partial class Extensions
{
    public static string ToTabified(this string input, int markerSpacing = 4)
    {
        return new string(tabEnumerable(input, markerSpacing).ToArray());
    }
 
    private static IEnumerable<char> tabEnumerable(
        IEnumerable<char> input,
        int markerSpacing)
    {
        var n = 0;
        using (var e = input.GetEnumerator())
            while (e.MoveNext())
            {
                if (e.Current == '\t')
                {
                    // at least one
                    yield return ' ';
                    n++;
 
                    // then fill to next marker
                    while (n % markerSpacing != 0)
                    {
                        yield return ' ';
                        n++;
                    }
                }
                else
                {
                    yield return e.Current;
                    n++;
                }
            }
    }
}
  Permalink  
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 5

This is fun. Must support and keep it going.
Assuming "every single tab is replaced with two spaces". A quick one in Python again.
"""
tabskiller.py
by Peter Leow the tabs assassin
 
"""
 
import re
 
def convertTabs2Spaces(m):
    # return 2 spaces to replace the spotted tab
    return " "*2
 
def main():
    # [ ][ ][tab]Hello, world!
    originalSentence = '  	Hello, world!'
    print('Testing 1,2,3...')
    print('Before:')
    print(originalSentence)
    print('After:')
    
    # tab in regex
    patternTab=r'\t'
 
    convertedSentence = re.sub(patternTab, convertTabs2Spaces, originalSentence)
    print(convertedSentence)
 
    print('UAT! Use Ctrl+Tab to enter a tab in the IDLE shell. Hit Enter-only to end. Enjoy...')
 
    while True:
        yourSentence = input('Input a sentence mixed with tabs and spaces:\n')
        if yourSentence == '':
            break
        convertedSentence = re.sub(patternTab, convertTabs2Spaces, yourSentence)
        print(convertedSentence)
  
main()

The output:
Testing 1,2,3...
Before:
  	    Hello, world!
After:
    Hello, world!
UAT! Use Ctrl+Tab to enter a tab. Hit Enter-only to end. Enjoy...
Input a sentence mixed with tabs and spaces:
			                Hello, world!
          Hello, world!
Input a sentence mixed with tabs and spaces:

Run it on a local IDLE not those online versions.
If I can find time, may come up another one using other languages. No promise though.
++++++++++++++++++++++++++++++++++++++
As promised, here comes the C# version:
/* 
 * TabsKiller.cs
 * by Peter Leow the tabs assassin
 */
 
using System;
using System.Text;
 
class TabsKiller
{
    static void Main(string[] args)
    {
        Console.WriteLine("Testing 1,2,3...");
        Console.WriteLine("Before");
        // [ ][ ][tab]Hello, world!
        string originalSentence = "  	Hello, world!";
        Console.WriteLine(originalSentence);
 
        Console.WriteLine("After");
        string convertedSentence = convertTabs2Spaces(originalSentence);
        Console.WriteLine(convertedSentence);
 
        Console.WriteLine("UAT! Hit Enter-only to end. Enjoy...");
        while (true)
        {
            Console.WriteLine("Input a sentence mixed with tabs and spaces:");
            string yourSentence = Console.ReadLine();
            if (yourSentence == string.Empty)
            {
                break;
            }
            Console.WriteLine(convertTabs2Spaces(yourSentence));
        }
    }
 
    static string convertTabs2Spaces(string sentence)
    {
        StringBuilder sb = new StringBuilder(sentence);
        // replace each tab with 2 spaces
        sb.Replace("\t", "  ");
        return sb.ToString();
    }
}
  Permalink  
v15
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 6

Just wanted to show that - even though many people say regex is so cool and elegant (???) - regex is sooo slow :-)

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text.RegularExpressions;
 
namespace CodingFromTheField.NukeStrings
{
    class Program
    {        
        static void Main(string[] args)
        {
            string input = "   \t\t \tHello, world!";
 
            Nuker nu = new Nuker();
 
            nu.NukeThis(input, "\t", "    ");
 
            input.WaitForUser();
        }
    }
 
    public class Nuker
    {
        public string OrgString { get; set; }
 
        protected Stopwatch Timer { get; set; }
 
        protected long RT1 { get; set; }
 
        protected long RT2 { get; set; }
 
        protected const int Iterations = 10000;
 
        protected Dictionary<string, string> Escaper = new Dictionary<string, string> { { " ", "[ ]" }, { "\t", "[tab]" } };
 
        public Nuker() { }
 
        public string NukeThis(string input, string replace, string replacement)
        {
            string ret = input;
 
            this.OrgString = ret;
 
            ret = Measure1(input, replace, replacement);
 
            Console.WriteLine("Measure1: \"{0}\".Replace(\"{1}\", \"{2}\") -> {3} ms ({4} iterations)",
                              input.Escape(Escaper), replace.Escape(Escaper), replacement.Escape(Escaper), this.RT1, Iterations);
 
            Console.WriteLine("\"{0}\" nuked to \"{1}\"", input.Escape(Escaper), ret.Escape(Escaper));
 
            Measure2(input, replace, replacement);
            
            Console.WriteLine("Measure1: Regex.Replace(\"{0}\", \"{1}\", \"{2}\") -> {3} ms ({4} iterations)",
                              input.Escape(Escaper), replace.Escape(Escaper), replacement.Escape(Escaper), this.RT2, Iterations);
 
            Console.WriteLine("\"{0}\" nuked to \"{1}\"", input.Escape(Escaper), ret.Escape(Escaper));
 
            long fact = this.RT2 / this.RT1;
 
            Console.WriteLine("String.Replace is ~{0} times {1} than Regex.Replace!", fact, (fact > 1) ? "faster" : "slower" );
 
            return ret;
        }
 
        protected string Measure1(string input, string replace, string replacement)
        {
            string ret = input;
 
            StartTimer();
 
            for (int cnt = 0; cnt <= Iterations; cnt++)
            { ret = input.Replace(replace, replacement); }
 
            this.RT1 = StopTimer();
 
            return ret;
        }
 
        protected string Measure2(string input, string replace, string replacement)
        {
            string ret = input;
 
            StartTimer();
 
            replace = Regex.Escape(replace);
 
            for (int cnt = 0; cnt <= Iterations; cnt++)
            { ret = Regex.Replace(input, replace + "[0-9]", replacement, RegexOptions.IgnoreCase); ; }
 
            this.RT2 = StopTimer();
 
            return ret;
        }
 
        protected void StartTimer()
        {
            if (this.Timer == null)
            { this.Timer = new Stopwatch(); }
 
            else
            { this.Timer.Reset(); }
 
            this.Timer.Start();
        }
 
        protected long StopTimer()
        {
            long ret = 0;
 
            if (this.Timer.IsRunning)
            {
                ret = this.Timer.ElapsedMilliseconds;
 
                this.Timer.Reset();
            }
 
            return ret;
        }
    }
 
    public static class ExtensionMethods
    {
        public static void WaitForUser(this object value)
        { Console.WriteLine("\r\npress any key to exit"); Console.ReadKey(); }
 
        public static string Escape(this string value, Dictionary<string, string> escaper)
        {
            string ret = value;
 
            foreach (KeyValuePair<string, string> kvp in escaper)
            { ret = ret.Replace(kvp.Key, kvp.Value); }
 
            return ret;
        }
    }
}
  Permalink  
Comments
ScottM1 2-Dec-16 4:59am
   
I think you may have read too much into it.
mfp-labs 2-Dec-16 6:28am
   
hehehe - as alwayws - code 'matures' while writing :-)
After starting with the regex implementation I thought, testing the performance diffs between direct string massage and regex would be a good idea.
Sharing the findings did sound like a good idea to me.

Btw. - Output
Measure1: "[ ][ ][ ][tab][tab][ ][tab]Hello,[ ]world!".Replace("[tab]", "[ ][ ][ ][ ]") -> 2 ms (10000 iterations)
"[ ][ ][ ][tab][tab][ ][tab]Hello,[ ]world!" nuked to "[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]Hello,[ ]world!"

Measure1: Regex.Replace("[ ][ ][ ][tab][tab][ ][tab]Hello,[ ]world!", "[tab]", "[ ][ ][ ][ ]") -> 16 ms (10000 iterations)
"[ ][ ][ ][tab][tab][ ][tab]Hello,[ ]world!" nuked to "[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]Hello,[ ]world!"

String.Replace is ~8 times faster than Regex.Replace!

press any key to exit

All the best
Michael
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 8

why not a VB.net one?

here:

Module Module1
 
     Sub Main()
          Dim TestStrings As New List(Of String)
          TestStrings.Add("[ ][ ][tab]Hello, world!")
          TestStrings.Add("[ ][ ][ ][tab][tab][ ][tab]Hello, world!")
 
          Const TabStopAt As Integer = 4
 
          Console.WriteLine("Running Tap Replacement Tests...")
          Console.WriteLine()
 
          RunTests(TestStrings, TabStopAt)
 
          Console.WriteLine()
          Console.WriteLine("Press any Key to end this App")
          Console.ReadKey()
     End Sub
 

     Sub RunTests(Tests As List(Of String), TapStop As Integer)
          For Each Test As String In Tests
               Console.WriteLine("Performing new Test!")
               Console.WriteLine("#####################")
               Console.WriteLine("Original String: {0}", Test)
               Test = RemoveDisplayStrings(Test)
               Console.WriteLine("Cleared String : {0}", Test)
               Test = ReplaceTabs(Test, TapStop)
               Console.WriteLine("Replaced String: {0}", Test)
               Test = AddDisplayStrings(Test)
               Console.WriteLine("Debug String   : {0}", Test)
               Console.WriteLine("#####################")
               Console.WriteLine()
          Next
     End Sub
 

     Function ReplaceTabs(Original As String, TabStop As Integer) As String
          Dim this As New List(Of Char)
          For Each c As Char In Original.ToCharArray
               If c = ControlChars.Tab Then
                    this.AddRange(New String(" "c, GetDiffToTabMarker(this.Count, TabStop)).ToCharArray)
               Else
                    this.Add(c)
               End If
          Next
 
          Return New String(this.ToArray)
     End Function
 

     Function GetDiffToTabMarker(Length As Integer, TabStop As Integer) As Integer
          Dim this As Integer = Length Mod TabStop
          If this > 0 Then this = TabStop - this
          If this = 0 Then this = TabStop
          Return this
     End Function
 
     Function RemoveDisplayStrings(Original As String) As String
          Return Original.Replace("[ ]", " ").Replace("[tab]", ControlChars.Tab)
     End Function
 
     Function AddDisplayStrings(Original As String) As String
          Return Original.Replace(" ", "[ ]").Replace(ControlChars.Tab, "[tab]")
     End Function
End Module



Output:
Running Tap Replacement Tests...
 
Performing new Test!
#####################
Original String: [ ][ ][tab]Hello, world!
Cleared String :   	Hello, world!
Replaced String:     Hello, world!
Debug String   : [ ][ ][ ][ ]Hello,[ ]world!
#####################
 
Performing new Test!
#####################
Original String: [ ][ ][ ][tab][tab][ ][tab]Hello, world!
Cleared String :    		 	Hello, world!
Replaced String:             Hello, world!
Debug String   : [ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]Hello,[ ]world!
#####################
 

Press any Key to end this App
  Permalink  
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 9

Time for good old plain C:
/* Replace tabs with spaces */
char *untab(int tabwidth, const char *src)
{
    int i, spaces;
    int pos = 0;
    int charpos = 0;
    char *dst;
 
    /* Allocate enough memory to untab a string containing only tabs */
    dst = (char *)malloc(tabwidth * strlen(src) + 1);
    while (*src)
    {
        switch (*src)
        {
        case '\t' :
            spaces = tabwidth - (linepos % tabwidth);
            for (i = 0; i < spaces; i++)
                dst[pos++] = ' ';
            charpos += spaces;
            break;
        case '\n' :
            charpos = -1;
        default :
            dst[pos++] = *src;
            ++charpos;
        }
        ++src;
    }
    dst[pos] = '\0';
    return dst;
}

Input / Output:
[ ][ ][tab]Hello,[ ]world!
[ ][ ][ ][ ]Hello,[ ]world!
    Hello, world!
[ ][ ][ ][tab][tab][ ][tab]Hello,[ ]world!
[ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]Hello,[ ]world!
            Hello, world!


When there is only one output channel (e.g. a file ) the untab() function may be changed to process only single characters and print the output directly when making charpos static. This would avoid allocating memory for each line. But I choosed the above solution to support formatted output and as it is.


For those who would like to reproduce it (may be enhanced to support reading from file, stdin, pipes and output to file):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
/* Insert untab() from above here */
 
void print(const char *s)
{
    int newline = 0;
    while (*s)
    {
        switch (*s)
        {
            case '\t' : printf("[tab]"); break;
            case ' '  : printf("[ ]"); break;
            case '\n' : newline = 1;
            default   : putchar(*s);
        }
        ++s;
    }
    /* Using puts("") here to print a system dependant newline */
    if (!newline)
        puts("");
}
 
void test(int tabwidth)
{
    char *untabbed;
    const char *test1 = "  \tHello, world!";
    const char *test2 = "   \t\t \tHello, world!";
 
    untabbed = untab(tabwidth, test1);
    print(test1);
    print(untabbed);
    printf("%s", untabbed);
    puts("");
    free(untabbed);
 
    untabbed = untab(tabwidth, test2);
    print(test2);
    print(untabbed);
    printf("%s", untabbed);
    puts("");
    free(untabbed);
}
 
int main()
{
    test(4);
    return 0;
}
  Permalink  
v3
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 11

With 3 lines of code and 25 bytes 
 
******************** File a.lex ********************
%{
/* Thanks to CPallini for pointing out a bug
   my vote for a T-Shirt is for him  */
%}
%%
\t printf(" ");
%%
******************** end of a.lex ********************
 
Compile & execute
flex a.lex
gcc lex.yy.c -lfl
./a.out < samples
 
where samples is a file containing all sorts of test strings with tabs and or spaces
 
Make it more fancy by adding new pattern recognition
A special return code like on last like int main(){return(yylex());}
.....
and so on., kind of freak though, had'nt used lex since years
  Permalink  
v2
Comments
CPallini 2-Dec-16 9:27am
   
syntax is not 100% correct (comments should written %{ ... %})
However the major problem of your code, is that it replaces every instance of a tab with four space. This is not the requested behavior (as far as I understand).
lbesteban 2-Dec-16 12:59pm
   
Yep, you're right, my mistake reading it
"Given a text string, convert the tabs to spaces. "

Proper solution is to print only one space. which reduces 3 bytes.

My bad, too anxious to see that actually something i had not used since left university in late 90's could be so quick to solve this.

******************** File a.lex ********************
%%
\t printf(" ");
%%
******************** end of a.lex ********************

And format is correct, this does not have comments

Yes, in flex you can have comments but a parser is defined as

[block of definitions]
%%
[block of token recognition]
%%
[a program logic]

Comments are like in any C language when enclosed in between %{ [...code lines... ]%}
CPallini 2-Dec-16 13:54pm
   
Indeed lex & bison were (are) fascinating.
:-)
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 12

it won't get the tshirt but cannot do without a VB6 solution :-)

disappointed I didn't get a goto in to the answer

Private Const TabStop = 4
Private Function TabExpand(strInput As String) As String
Dim i As Integer, col As Integer, tabFound As Integer, StartPos As Integer, Padlen As Integer
Dim strOutput As String
    StartPos = 1
    tabFound = InStr(StartPos, strInput, vbTab)
    If tabFound = 0 Then
        TabExpand = strInput
        Exit Function
    End If
    Do While tabFound > 0
        strOutput = strOutput & Mid(strInput, StartPos, tabFound - StartPos)
        Padlen = TabStop - (Len(strOutput) Mod TabStop)
        strOutput = strOutput & Space(Padlen)
        StartPos = tabFound + 1
        tabFound = InStr(StartPos, strInput, vbTab)
    Loop
    If StartPos < Len(strInput) Then
        strOutput = strOutput & Mid(strInput, StartPos)
    End If
    TabExpand = strOutput
End Function
  Permalink  
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 13

using System.Text;
using NUnit.Framework;
namespace Code_Project_Challenge
{
    class TabConverter
    {
        static int tabLength = 4;
        public string Convert(string str)
        {
            var sb = new StringBuilder(str.Length);
            int charCount = 0, spacesToAdd;
 
            foreach (var c in str)
            {
                if (c == '\t')
                {
                    spacesToAdd = tabLength - (charCount % tabLength);
                    sb.Append(' ', spacesToAdd);
                    charCount += spacesToAdd;
                }
                else
                {
                    sb.Append(c);
                    charCount++;
                }
            }
 
            return sb.ToString();
        }
    }
 
    [TestFixture]
    public class TabConverterTest
    {
        [Test]
        [TestCase("  \tHello, world!", "    Hello, world!")]
        [TestCase("   \t\t \tHello, world!", "            Hello, world!")]
        public void Returns(string inStr, string expected)
        {
            var sut = new TabConverter();
            var result = sut.Convert(inStr);
            Assert.AreEqual(expected, result);
        }
    }
}
  Permalink  
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 14

Lua:
local function tab2blank(s)
  local n=1
  return s:gsub('(.-)\t', function(s) n = n + #s; b = 4 - (n-1) % 4; n = n + b; return s.. string.rep(' ', b) end)
end


Test program:
local function format(s)
  return s:gsub("([ \t])", function (p) return p == ' ' and '[ ]' or '[tab]' end )
end
 
local t = { "  \tHello, world!", "   \t\t \tHello, world!" }
 
local function tab2blank(s)
  local n=1
  return s:gsub('(.-)\t', function(s) n = n + #s; b = 4 - (n-1) % 4; n = n + b; return s.. string.rep(' ', b) end)
end
 
for k,s in ipairs(t) do
  print("item " .. k .. ":")
  print(format(s) .. " -> " .. format(tab2blank(s)))
end

Output:
item 1:
[ ][ ][tab]Hello,[ ]world! -> [ ][ ][ ][ ]Hello,[ ]world!
item 2:
[ ][ ][ ][tab][tab][ ][tab]Hello,[ ]world! -> [ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]Hello,[ ]world!
  Permalink  
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 15

The code:

static string ReplaceTabWithSpaces(string text)
{
	var spaceCount = 0;
	var builder = new StringBuilder();
	for (var pos = 0; pos < text.Length; pos++)
	{
		if (text[pos] == ' ')
		{
			spaceCount++;
			if (spaceCount == 4)
			{
				spaceCount = 0;
				builder.Append("    ");
			}
		}
		else if (text[pos] == '\t')
		{
			builder.Append("    ");
			spaceCount = 0;
		}
		else
		{
			if (spaceCount > 0)
			{
				builder.Append(string.Empty.PadLeft(spaceCount));
				spaceCount = 0;
			}
			builder.Append(text[pos]);
		}
	}
	if (spaceCount > 0)
	{
		builder.Append(string.Empty.PadLeft(spaceCount));
	}
	return builder.ToString();
}
 
static string Decode(string text)
{
	return text.Replace("[ ]", " ").Replace("[tab]", "\t");
}
 
static string Encode(string text)
{
	return text.Replace(" ", "[ ]").Replace("\t", "[tab]");
}
 
static void Main(string[] args)
{
	var text = "[ ][ ][tab]Hello, world!";
	Console.WriteLine("Input : {0}", text);
	Console.WriteLine("Output: {0}", Encode(ReplaceTabWithSpaces(Decode(text))));
 
	text = "[ ][ ][ ][tab][tab][ ][tab]Hello, world!";
	Console.WriteLine("Input : {0}", text);
	Console.WriteLine("Output: {0}", Encode(ReplaceTabWithSpaces(Decode(text))));
 
	Console.ReadLine();
}


Output:

Input : [ ][ ][tab]Hello, world!
Output: [ ][ ][ ][ ]Hello,[ ]world!
Input : [ ][ ][ ][tab][tab][ ][tab]Hello, world!
Output: [ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]Hello,[ ]world!
  Permalink  
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 16

I have included 2 version: ExpandSimple for traditional; & ExpandCompact for something a little different.

Code:

    class Program
    {
        static void Main(string[] args)
        {
            int tabstopSize = 4;
 
            string Test1 = "  \tHello, World!";
            string validate1 = "    Hello, World!";
 
            string Test2 = "   \t\t \tHello, world!";
 
            string result1a = Test1.ExpandSimple(tabstopSize);
 
            Console.WriteLine($"Simple 1       Before : {Test1.ShowSpacing()}");
            Console.WriteLine($"                After : {result1a.ShowSpacing()}");
            Console.WriteLine($"              Passed? : {result1a.Equals(validate1)}");
            Console.WriteLine("");
 
            string result1b = Test1.ExpandCompact(tabstopSize);
 
            Console.WriteLine($"Compact 1      Before : {Test1.ShowSpacing()}");
            Console.WriteLine($"                After : {result1b.ShowSpacing()}");
            Console.WriteLine($"              Passed? : {result1b.Equals(validate1)}");
            Console.WriteLine("");
            Console.WriteLine($"Simple 1 = Compact 1? : {result1a.Equals(result1b)}");
            Console.WriteLine("");
 
            string result2a = Test2.ExpandSimple(tabstopSize);
 
            Console.WriteLine($"Simple 2       Before : {Test2.ShowSpacing()}");
            Console.WriteLine($"                After : {result2a.ShowSpacing()}");
            Console.WriteLine("");
 
            string result2b = Test2.ExpandCompact(tabstopSize);
 
            Console.WriteLine($"Compact 2      Before : {Test2.ShowSpacing()}");
            Console.WriteLine($"                After : {result2b.ShowSpacing()}");
            Console.WriteLine("");
            Console.WriteLine($"Simple 2 = Compact 2? : {result2a.Equals(result2b)}");
            Console.WriteLine("");
 
            Console.WriteLine("-- Press any key to exit --");
            Console.ReadKey();
        }
    }
 
    static class Extensions
    {
        public static string ExpandSimple(this string input, int tabstopSize)
        {
            int count = 0, pos = 0, inputLength = input.Length;
            var chars = input.ToCharArray();
            var output = new Stack<char>();
 
            while (pos < inputLength)
            {
                if (chars[pos] == ' ')
                {
                    output.Push(chars[pos]);
                    count++;
                }
                else if (chars[pos] == '\t')
                {
                    for (int i = 0; i < tabstopSize - count; i++)
                        output.Push(' ');
                    count = 0;
                }
                else
                {
                    break;
                }
                pos++;
            }
            return (new StringBuilder()).Append(new string(output.Select(x => x).ToArray())).Append(new string(chars.Skip(pos).Take(inputLength - pos).ToArray())).ToString();
        }
 
        public static string ExpandCompact(this string input, int tabstopSize)
        {
            int index = 0;
            return string.Join(string.Empty, input.ToCharArray().Select((x) => x.Equals('\t') ? x.ConvertTabChar(ref index, tabstopSize) : x.ConvertNormChar(ref index)).ToArray());
        }
 
        public static string ConvertNormChar(this char c, ref int count)
        {
            count++;
            return new string(new char[] { c });
        }
 
        public static string ConvertTabChar(this char c, ref int count, int tabstopSize)
        {
            int pad = tabstopSize - count % tabstopSize;
            count += pad;
            return new string(Enumerable.Repeat(' ', pad).ToArray());
        }
 
        public static string ShowSpacing(this string input)
        {
            int pos = 0, inputLength = input.Length;
            var chars = input.ToCharArray();
            var sb = new StringBuilder();
            while (pos < inputLength)
            {
                if (chars[pos] == ' ')
                {
                    sb.Append("[ ]");
                }
                else if (chars[pos] == '\t')
                {
                    sb.Append(@"[tab]");
                }
                else
                {
                    sb.Append(new string(chars.Skip(pos).Take(inputLength - pos).ToArray()));
                    break;
                }
                pos++;
            }
            return sb.ToString();
        }
    }


Output:

Simple 1       Before : [ ][ ][tab]Hello, World!
                After : [ ][ ][ ][ ]Hello, World!
              Passed? : True
 
Compact 1      Before : [ ][ ][tab]Hello, World!
                After : [ ][ ][ ][ ]Hello, World!
              Passed? : True
 
Simple 1 = Compact 1? : True
 
Simple 2       Before : [ ][ ][ ][tab][tab][ ][tab]Hello, world!
                After : [ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]Hello, world!
 
Compact 2      Before : [ ][ ][ ][tab][tab][ ][tab]Hello, world!
                After : [ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]Hello, world!
 
Simple 2 = Compact 2? : True
 
-- Press any key to exit --
  Permalink  
v3
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 19

QBASIC baby! My dad would be so proud. Hah.

DIM TABBYTABS$
DIM SPACYMCSPACE$
TABBYTABS$ = "   " + CHR$(9) + CHR$(9) + " " + CHR$(9) + "Hello World!"
FOR I = 1 TO LEN(TABBYTABS$) STEP 1
    IF ASC(MID$(TABBYTABS$, I, 1)) = 9 THEN
        SPACYMCSPACE$ = SPACYMCSPACE$ + " "
    ELSE
        SPACYMCSPACE$ = SPACYMCSPACE$ + MID$(TABBYTABS$, I, 1)
    END IF
NEXT I
PRINT TABBYTABS$
PRINT SPACYMCSPACE$
  Permalink  
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 36

In javascript his can be done with a single compound statement. By using indexOf function we can determine the position of the tab character by this expression
tabPosition=theText.indexOf("\t")
which gives us a zero-indexed position or -1 if there are no remaining tabs.

The number of spaces we need to add will be at most four, but we should trim that by the remainder of tabPosition divided by 4 (i.e. tabPosition%4), so that the total number of characters after the replacement is an exact multiple of 4 characters. i.e. we should replace the tab character by this string expression:
("    ").substr(0,4-tabPosition%4)

There may be more than one tab in the text so we should repeat the replacement as long as tabPosition isn't -1. Putting that all together gives:

while((tabPosition=theText.indexOf("\t"))!=-1)theText=theText.replace("\t",("    ").substr(0,4-tabPosition%4));


That single line is all we need to covnvert theText into a tabbed-by-indiviudal-space-characters version. Obviously it's more useful as a function, but why not add a bit more functionality so that tabs can be 2, 3, 4 ....12 character positions apart? We just need to replace the number 4 in our coumpund statement by a variable, and make whitespace string contain more space characters.
function tabs2Spaces(theText,tabSpacing)
{
	while((tabPosition=theText.indexOf("\t"))!=-1)theText=theText.replace("\t",("            ").substr(0,tabSpacing-tabPosition%tabSpacing));
	return theText;
}
 
// show how the function can align tab spaces irrespective of no of characters before:
document.writeln ("Using tab positions 4 characters apart:")
document.writeln(tabs2Spaces("\tHello World",4));
document.writeln(tabs2Spaces("  \tHello World",4));
document.writeln(tabs2Spaces("  \tHello World",4));
document.writeln(tabs2Spaces("   \tHello World",4));
document.writeln(tabs2Spaces("    \tHello World",4));
document.writeln(tabs2Spaces("     \tHello World",4));
document.writeln(tabs2Spaces("      \tHello World",4));
document.writeln(tabs2Spaces("       \tHello World",4));
document.writeln ("Using tab positions 6 characters apart:")
document.writeln(tabs2Spaces("\tHello World",6));
document.writeln(tabs2Spaces("  \tHello World",6));
document.writeln(tabs2Spaces("  \tHello World",6));
document.writeln(tabs2Spaces("   \tHello World",6));
document.writeln(tabs2Spaces("    \tHello World",6));
document.writeln(tabs2Spaces("     \tHello World",6));
document.writeln(tabs2Spaces("      \tHello World",6));
document.writeln(tabs2Spaces("       \tHello World",6));
document.writeln ("Using tab positions 9 characters apart:")
document.writeln(tabs2Spaces("\tHello World",9));
document.writeln(tabs2Spaces("  \tHello World",9));
document.writeln(tabs2Spaces("  \tHello World",9));
document.writeln(tabs2Spaces("   \tHello World",9));
document.writeln(tabs2Spaces("    \tHello World",9));
document.writeln(tabs2Spaces("     \tHello World",9));
document.writeln(tabs2Spaces("      \tHello World",9));
document.writeln(tabs2Spaces("       \tHello World",9));


.... which outputs this text ...
Using tab positions 4 characters apart:
    Hello World
    Hello World
    Hello World
    Hello World
        Hello World
        Hello World
        Hello World
        Hello World
Using tab positions 6 characters apart:
      Hello World
      Hello World
      Hello World
      Hello World
      Hello World
      Hello World
            Hello World
            Hello World
Using tab positions 9 characters apart:
         Hello World
         Hello World
         Hello World
         Hello World
         Hello World
         Hello World
         Hello World
         Hello World
  Permalink  
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 7

Quick and dirty javascript

var TAB_LEN = 4;
// The function
function tabs2Spaces (str){
	return str.replace(/^([\ \t]+)/, (m, p)=>{
		return p.split('').reduce((p, q) => { 
			return q==' '?p+q : p+' '.repeat(TAB_LEN - p.length % TAB_LEN); 
		}, '');
	});
}
// The test
function showSpaces(str){
	return str.replace(/^([\ \t]+)/, (m, p)=>{
		return p.replace(/\ /g, '[ ]').replace(/\t/g, '[tab]');
	});	
}
var tests = ['  	Hello, world!', '   		 	Hello, World!'];
tests.forEach( s=> { 
	console.log('Before:\t' + showSpaces(s));
	console.log('After:\t' + showSpaces(tabs2Spaces(s)));
});
/* OUTPUT
Before: [ ][ ][tab]Hello, world!
After:  [ ][ ][ ][ ]Hello, world!
Before: [ ][ ][ ][tab][tab][ ][tab]Hello, World!
After:  [ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ][ ]Hello, World!
*/
  Permalink  
v2
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 2

body {
  tab-size: 4;
}
  Permalink  
v2
Comments
ppolymorphe 3-Dec-16 14:09pm
   
I fear it is not so simple.
Kornfeld Eliyahu Peter 3-Dec-16 15:03pm
   
And CSS is NOT a programming language...
I tried to make a joke at 01:30 (night), but it was as bad as my mood :-)
ppolymorphe 3-Dec-16 15:25pm
   
:-)
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 4

setlocal enabledelayedexpansion
for /f "tokens=*" %%a in (h:\myFile.txt) do (
set row=%%a
set row=!row:,= !
echo.!row!>>h:\changed.txt
)

put text in myfile.txt
save as xxx.bat and run via windows command prompt
it replaces spaces with tabs - because otherwise
  Permalink  
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 18

String extension with nice turtle pace immutable string manipulation.

public static string RemoveTabs(this string input) {
    if (string.IsNullOrWhiteSpace(input)) {
         return input;
    }
 
    int idx = 0;
 
    while (true) {
        if (idx >= input.Length) {
            break;
        }
 
        if (input[idx] == '\t') {
            input = input.Remove(idx, 1);
            int cur = idx;
 
            while (cur < idx + 4) {
                input = input.Insert(cur, '[ ]');
                cur++;
            }
 
            idx += 4;
            continue;
        }
 
        idx++;
    }
 
    input = input.Replace("[tab]", "[ ][ ][ ][ ]");
 
    return input;
}


Use:
string test = "CONVERT\tTABS\t\t-\tTo SPACES".RemoveTabs();
Console.WriteLine(test);
// Or
test = "CONVERT\tTABS\t\t-\tTo SPACES";
test = test.RemoveTabs();
Console.WriteLine(test);


Had to add a second.. ILE RPG (UNTESTED)

D test S 45A   INZ('CONVERT x'05' TABS x'05'- x'05' To SPACES') VARYING
D tester S 45A   INZ('CONVERT [tab] TABS [tab]- [tab] To SPACES') VARYING
test = %ScanRpl(x'05' : '[ ][ ][ ][ ]' : test);
tester = %ScanRpl('[tab]' : '[ ][ ][ ][ ]' : tester);


Ruby

test = "CONVERT [tab] TABS [tab]- [tab] To SPACES"
test = test.gsub("[tab]", "[ ][ ][ ][ ]")
  Permalink  
v6
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 20

LINQy version of my previous solution. It works properly for tabs placed anywhere in the text, always aligning to %4 (or %tabLength).

using System.Linq;
using NUnit.Framework;
namespace Code_Project_Challenge
{
    class TabConverter
    {
        static int tabLength = 4;
 
        public string Convert(string str)
        {
            int charCount = 0, spacesToAdd;
 
            return string.Join("", str.Select(ch => {
                if (ch == '\t')
                {
                    spacesToAdd = tabLength - (charCount % tabLength);
                    charCount += spacesToAdd;
                    return new string(' ', spacesToAdd);
                }
                else
                {
                    charCount++;
                    return ch.ToString();
                }
            }));
        }
    }
 
    [TestFixture]
    public class TabConverterTest
    {
        [Test]
        [TestCase("  \tHello, world!", "    Hello, world!")]
        [TestCase("   \t\t \tHello, world!", "            Hello, world!")]
        [TestCase("   \ta     \t \tHello\t, world!", "    a           Hello   , world!")]
        public void Returns(string inStr, string expected)
        {
            var sut = new TabConverter();
            var result = sut.Convert(inStr);
            Assert.AreEqual(expected, result);
        }
    }
}
  Permalink  
Comments
Graeme_Grant 2-Dec-16 12:52pm
   
Looks awfully close to what I had above with ExpandCompact...
Jacek Glen 5-Dec-16 6:42am
   
Oh, I missed your solution before posting mine.
Indeed, the approach is very similar. Seems great minds think alike ;)

losvce 5-Dec-16 10:08am
   
This LINQy version is far, far better than what I tried in my solution. I just couldn't get it to work in the time I spent on it. Thanks for the perspective!
Page 1 of 3
1 2 3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


Advertise | Privacy |
Web03 | 2.8.171020.1 | Last Updated 7 Dec 2016
Copyright © CodeProject, 1999-2017
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100