Word Blocks in TMemo

I'm trying to make a basic Hex viewer from TMemo, I know that this is probably not perfect, but I will use it only personally so that it does not matter.

(1)

First, suppose Memo is filled with hexadecimal information like this:

enter image description here

How can I get the number of all displayed text blocks ignoring a space? Thus, using the image, the result in this case will be 28.

This is what I tried, and I know that this is completely wrong, as I access Memo strings, but I don’t know how to access each character.

I can not solve this simple problem :(

function CountWordBlocks(Memo: TMemo): Integer; var i: Integer; vCount: Integer; begin for i := 0 to Memo.Lines.Count - 1 do begin if Length(Memo.Lines.Strings[i]) = 2 then begin Inc(vCount); end; end; Result := vCount; end; 

Here is the code that I use to display Hex values ​​in Memo:

 procedure ReadFileAsHex(const AFileName: string; ADestination: TStrings); var fs: TFileStream; buff: Byte; linecount: Byte; line: string; begin linecount := 0; line := ''; fs := TFileStream.Create(AFileName, fmOpenRead); try ADestination.BeginUpdate; try while fs.Position < fs.Size do begin fs.Read(buff, 1); line := line + IntToHex(buff, 2) + ' '; Inc(linecount); if linecount = 16 then begin ADestination.Add(line); line := ''; linecount := 0; end; end; if Length(line) <> 0 then ADestination.Add(line); finally ADestination.EndUpdate; end; finally fs.Free; end; end; 

(2)

If I click Memo and the text block is under the cursor, how can I find out which number of the highlighted block belongs to everyone else?

Thus, using the same first image, the carriage is on the top line next to 68, so the result will be 3, as this is the third text block of 28.

It should be so simple, but I can’t think clearly, I don’t have the right programming yet, and I am really struggling with basic logic and problem solving!

(3)

Finally, I would like to select a block at runtime by passing the value of the block number. I tried this without much success:

 procedure FindBlock(Memo: TMemo; BlockNumber: Integer); var i: Integer; txt: string; ThisWhite, PrevWhite: boolean; vRead: Integer; begin txt := Memo.Text; vRead:= 0; PrevWhite := True; for i := 1 to Length(txt) do begin ThisWhite := Character.IsWhiteSpace(txt[i]); if PrevWhite and not ThisWhite then begin Inc(vRead); PrevWhite := False; end; PrevWhite := ThisWhite; if vRead = BlockNumber then begin Memo.SelStart := vRead; Memo.SetFocus; Exit; end; end; end; 
+4
source share
2 answers

(1)

It works:

 function TForm1.CountBlocks: integer; var i: Integer; txt: string; ThisWhite, PrevWhite: boolean; begin txt := Memo1.Text; result:= 0; PrevWhite := true; for i := 1 to Length(txt) do begin ThisWhite := Character.IsWhiteSpace(txt[i]); if PrevWhite and not ThisWhite then begin inc(result); PrevWhite := false; end; PrevWhite := ThisWhite; end; end; 

However, it can be optimized if more detailed information about the contents of the note is available. For example, if you know that each line consists of four blocks, then the number of blocks is just 4*Memo1.Lines.Count . My code above will even accept blocks of different widths.

(2)

Just replace

 for i := 1 to Length(txt) do 

by

 for i := 1 to Memo1.SelStart + 1 do 
+6
source

Since you control the formatting of your lines, and the lines have a fixed format, it is very simple to calculate the number of bytes displayed without resorting to cyclic transition on individual lines once. Each line maps 3 characters per byte, and each line different from the last line maps 16 bytes, thus 48 characters per 16-byte line. Take advantage of these facts to calculate the number of bytes based on the number of full 16 byte strings, and then you can add the number of bytes remaining from only the last line:

 function CountWordBlocks(Memo: TMemo): Integer; var Count: Integer; begin Count := Memo.Lines.Count; if Count > 0 then Result := (16 * (Count-1)) + (Length(Memo.Lines[Count-1]) div 3); else Result := 0; end; 

You can do something like this to translate the character offset inside Memo into the work block number:

 function GetCurrentWordBlock(Memo: TMemo): Integer; var SelStart, LineStart, LineNum: Integer begin Result := 0; SelStart := Memo.SelStart; if SelStart < 0 then Exit; LineStart := Memo.Perform(EM_LINEINDEX, SelStart, 0); if LineStart < 0 then Exit; LineNum := Memo.Perform(EM_LINEFROMCHAR, LineStart, 0); Result := (16 * LineNum) + ((SelStart - LineStart) div 3) + 1; end; 

To select a given block number, you can do this:

 procedure FindBlock(Memo: TMemo; BlockNumber: Integer); var LineNum, LineStart: Integer; begin if BlockNumber < 1 then Exit; LineNum = (BlockNumber - 1) div 16; LineStart = Memo.Perform(EM_LINEINDEX, LineNum, 0); if LineStart < 0 then Exit; Memo.SelStart = LineStart + (((BlockNumber - 1) - (16 * LineNum)) * 3); Memo.SelLength := 2; Memo.SetFocus; end; 
+2
source

Source: https://habr.com/ru/post/1400482/


All Articles