Link to home
Start Free TrialLog in
Avatar of Ridey
Ridey

asked on

Finding the width of a tab char - tab width

Hi everyone

If a file exists that have multiple lines of (can be of any value) however each string contains tab chars of variable length.
I need to replace the tab values with equivelant spaces so that the file looks the same.

Let me try and visually display this for you.

abcde+#9+ abcde+#9+#9+a (on this line the tab values are all a width of 4)
abcde+#9+ abcde+#9+#9+a (on this line the first tab has a width of 3 the second a width of 5 and the the 3rd a width of 4)
abcde+#9+ abcde+#9+#9+a (on this line the first tab has a width of 8 the second a width of 2 and the the 3rd a width of 4)
abcde+#9+ abcde+#9+#9+a (on this line the first tab has a width of 5 the second a width of 4 and the the 3rd a width of 4)

now for me to make the resulting file look the same i would need to rplace each tab with enough spaces to make up th width of the tab char.

In the real life enviroment I would not know where the tabs exist in the file no would i know in advance what the width value of the tab chars would be. I can not import the file into a visual control and variable fonts would not be an issue. Thus what i need is an algorithym of some type the produce the result that i need.

Your help as always will be appreciated.
Avatar of ZhaawZ
ZhaawZ
Flag of Latvia image

As far as I know, width of tab-char depends on editor that you're using to view contents of a file.
If you're using Notepad, it also depends on a font - different fonts show different result.
Avatar of quilley
quilley

> nor would i know in advance what the width value of the tab chars would be

In order to solve this problem there must be a way of discovering the tab widths. Are they contained in the data? If so, how are they encoded? If not, how does the application displaying the existing data know how wide the tabs are?
hmm... if you want to replace those tabs with spaces, i suppose that you want to get the resulting text that looks like table, right? with rows and fine columns.
in this case calculating width of each column (in chars) would be better than calculating width of tabs.
Avatar of Ridey

ASKER

quilley

The file when read as a text file indicates the tab chars only as #9, however when opening the file in notepad the tab widths differ, fundamentally the problem is that I do not know how to identify the widthof the tab chars as there is no indication of the actual width when using readln.

Zhaawz

I know that the font influences the tab width, and that is why i want to do the conversion without using a visual component.

The table is only an indication of where the tab chars would be in the line and what the width of the tab would be. In other words what I want the resulting text file to be is as follows :
abcde     abcde        a
abcde    abcde         a
abcde         abcde      a
abcde      abcde        a

this however is only an example since the tab char can be anyware in the actual line of text(string).


Thanks for the intrest shown so far.
Regards
Er... now I think I understand what you're after. If you calculate a maximum value for the width of a field based on the data in the file, you can format it by padding the fields with spaces up to that width.

Here's my solution; to try it paste two Memo controls on a form, add the functions and event procedures below, run the program and paste your data into Memo1.

function MaxFieldWidth(const S: string): Integer;
var
  N, Count: integer;
begin
  Result := 0;
  Count := 0;

  for N := 1 to Length(S) do
    if S[N] in [#9, #10, #13] then
    begin
      if Count > Result then
        Result := Count;
      Count := 0
    end
    else
      Inc(Count);

  if Count > Result then
    Result := Count;
end;

function ReplaceTabs(const S: string; Width: Integer): string;
var
  N, Start: integer;
begin
  Result := '';
  Start := 1;

  for N := 1 to Length(S) do
    if S[N] in [#9, #10, #13] then
    begin
      Result := Result + Copy(S, Start, N - Start);
      if S[N] = #9 then
        Result := Result + StringOfChar(' ', Width + Start - N)
      else
        Result := Result + S[N];
      Start := N + 1;
    end;

  Result := Result + Copy(S, Start, MaxInt);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Font.Name := 'Courier New';
  Memo2.Font.Name := 'Courier New';
  Memo1.WantTabs := True;
end;

procedure TForm1.Memo1Change(Sender: TObject);
begin
  with Memo1 do
    Memo2.Text := ReplaceTabs(Text, MaxFieldWidth(Text) + 4);
end;

Note 1: The "+ 4" in the last line is the number of *extra* spaces to add between columns.

Note 2: This code uses the same width for all columns. It's possible to calculate a different width for each column, but I thought that might complicate things unnecessarily.
ASKER CERTIFIED SOLUTION
Avatar of quilley
quilley

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sorry, forgot to free object in example:

  TabList := TTabList.Create;
  with TabList do
  try
    LoadFromFile('Test.txt');
    for N := 0 to Count - 1 do
      ListBox1.Items.Add(Fields[N, 0]);    // 0 = First column
  finally
    Free;
  end;

Better?