Send strings terminated with [CR][LF] - string

My app sends NMEA strings terminated with [CR]+[LF].
The NMEA standard specifies this format (example is heading info from a gyro compass): '$HEHDT,2.0,T*2D[CR][LF]'.
At the receiving end the string is discarded as incomplete.
How do I append and send these characters?
Sending is straight forward with only a few lines of code (Object is Cp1tx: TIdUDPServer;):
...
Cp1tx.Active:= true;
Cp1tx.Broadcast(InStr,8051,'',IndyTextEncoding_8Bit);
Cp1tx.Active:= false;
...
Btw, I am using Delphi 10.1 Berlin.

Assumming that the InStr is the string you want to send it would be :
Cp1tx.Broadcast(InStr + #13#10, 8051, '', IndyTextEncoding_8Bit);

There are different ways to express CRLF:
Instr := '$HEHDT,2.0,T*2D'#13#10;
Instr := '$HEHDT,2.0,T*2D'#$D#$A;
// CR and LF are defined in the IdGlobal unit
Instr := '$HEHDT,2.0,T*2D'+CR+LF;
// EOL is defined in the IdGlobal unit
Instr := '$HEHDT,2.0,T*2D'+EOL;

Thanks to all of you.
I think I made a fool of myself. It runs ok now no matter how I add the CRLF chars.
A historical comment:
CRLF (and in that order!) was invented for use in the old, mechanical telex machines powered by a 1/2 HP motor. It took time to move the carriage back to the left position. That's why CR is send first and then LF, so all the mechanics have time to align and get ready to print the first character on the new line.
Novice telex operators learned it the hard way. Sending LF and CR and then typing text trapped the carriage on its way to the left, the type arms tangled and often the drive axle jammed or broke. Remember this was high speed transmission on astonishing 50 Baud! I spend endless hours in my service repairing broke telex machines. Well, things are different and better nowadays, but we still stick to the old CRLF convention.

When I need to send CR+LF often I declare a Const and refer to it as needed.
Const
CRLF = #13+#10;
{ To use this do the following }
MyString := 'This string ends with a Carriage Return / Line Feed'+CRLF;
You can also add Carriage Return / Linefeed using Chr(10)+Chr(13);
For example;
MyString := 'This string also ends with a CRLF' + Chr(10) + Chr(13)
+ 'But it could equally end with an Escape Code' + Chr(27) // or #27
I have edited my answer because it was pointed out I had the CR LF in the wrong order.

Related

Writing Bytes to strings.builder prints nothing

I am learning go and am unsure why this piece of code prints nothing
package main
import (
"strings"
)
func main(){
var sb strings.Builder
sb.WriteByte(byte(127))
println(sb.String())
}
I would expect it to print 127
You are appending a byte to the string's buffer, not the characters "127".
Since Go strings are UTF-8, any number <=127 will be the same character as that number in ASCII. As you can see in this ASCII chart, 127 will get you the "delete" character. Since "delete" is a non-printable character, println doesn't output anything.
Here's an example of doing the same thing from your question, but using a printable character. 90 for "Z". You can see that it does print out Z.
If you want to append the characters "127" you can use sb.WriteString("127") or sb.Write([]byte("127")). If you want to append the string representation of a byte, you might want to look at using fmt.Sprintf.
Note: I'm not an expert on character encoding so apologies if the terminology in this answer is incorrect.

AHK: Remove Text From String This Word To The First Line Break

I work at a doctors office doing billing, and I've run into a problem. Because of an issue with the way the EMR (electronic medical record) program works, immunization codes don't always make it into the chart. In order to compensate for this, I have AHK also search for the name of the immunization (dangerous, I know). Just until recently, this was working fine, until one of the doctors canceled an order for an immunization. This threw a false positive because of the failsafe I included for the charts without the code (IMM94, and IMM97). I need to remove, from a very large string, everything after the word "CANCELED: " to the first line break that occurs after that word. I created a rather pretty string clipping function to do most of this kind of stuff, but it's taking issue with finding the line break because there are so many. The test case I'm working with is:
Assessment and Plan:
Need for prophylactic vaccination and inoculation against influenza (tab) CANCELED: Influenza, High Dose (65+) (newline)
Prediabetes Work on weight loss and exercise
Osteopenia Exercise and vit d and b 12
There's a lot of stuff both above this, and below this, but I want to extract ALL instances from my string of the word "CANCELED: " to the first line break after it.
This is what I'm trying, along with my function. It's not working, and in fact, it's duplicating the line beginning with "1. ":
^L::
lString := ClipBoard
If lString Contains Canceled
fString := ClipString(lString, "CANCELED: ", "`n")
Clipboard := fString
Return
ClipString(lString, aMarker, bMarker, Only := 0)
{
If (Only = 1)
Return SubStr(SubStr(lString, 1, InStr(lString, bMarker)+StrLen(bMarker)-1), InStr(lString, aMarker))
Else
Return SubStr(lString, 1, InStr(lString, aMarker)-StrLen(aMarker)) . SubStr(lString, InStr(lString, bMarker)+StrLen(bMarker))
}
Strips "cancelled:" and any text following it from each line in clipboard
Program:
Clipboard := RegExReplace(Clipboard, "im)\s*CANCELLED:.*\R?", "`r`n")
Sample Input:
alpha
beta cancelled: ABC asldkfalsd
delta
gamma omega CANCELLed: zeta
theta
Sample Output:
alpha
beta
delta
gamma omega
theta
Got it figured out. I'll comment it to help anyone who has this issue. I love how compact you can get functions usually, but this piece really needed a couple more lines than I'd like. If anyone can get it down to less, and have it still work, let me know!
^L::
ClipBoard := ClipString(ClipBoard, "Canceled: ", "`n",2) ;This is the function call here.
;The first parameter is the string to do stuff to, the second is what to cut out of the
;string, and the third parameter is how far after that piece to cut, so if you wrote
;Canceled: thenawholebunchofstuffthena newline, it'd remove all of it except for the
;newline. The third parameter is which mode to put ClipString to.
Return
ClipString(lString, aMarker, bMarker, Mode := 0) ;already explained above.
;Mode defaults to zero because I call the zero mode a lot.
{
If (Mode = 0) ;Mode Zero returns the ONLY the section from the original string
;between aMarker and bMarker.
Return SubStr(lString, 1, InStr(lString, aMarker)-StrLen(aMarker)) . SubStr(lString, InStr(lString, bMarker)+StrLen(bMarker))
Else If (Mode = 1) ;Mode One returns the original string with the section between aMarker
;and bMarker removed.
Return SubStr(SubStr(lString, 1, InStr(lString, bMarker)+StrLen(bMarker)-1), InStr(lString, aMarker))
Else If (Mode = 2) ;Mode Two returns the original string with all instances of aMarker
;to bMarker removed. I.E. Every occurrence of aMarker will be removed to bMarker.
{
aString := lString
StringReplace, aString, aString, %aMarker%, %aMarker%, UseErrorLevel ;Count how many
;instances of aMarker are in the original string.
CanCnt := Errorlevel ;actual count of # of aMarkers
Loop, %CanCnt% ;loop as many times as there are aMarkers
{
aString := SubStr(aString, 1, InStr(aString, aMarker)-1) . SubStr(SubStr(aString, InStr(aString, aMarker)), InStr(SubStr(aString, InStr(aString, aMarker)), bMarker)-1)
;this is a tad complicated. The first part before the concatenate takes the string, and
;keeps from the start point to the first aMarker. The concatenate adds the substring of the
;substring between aMarker and the end of the string, and the location of the substring in
;aString from the occurrence of aMarker to one position before the start of bMarker.
;An easier way to read this would be to replace "SubStr(aString, InStr(aString, aMarker))
;with a variable like bString. It shortens it up quite a bit.
}
Return aString
}
}

Golang: Issues replacing newlines in a string from a text file

I've been trying to have a File be read, which will then put the read material into a string. Then the string will get split by line into multiple strings:
absPath, _ := filepath.Abs("../Go/input.txt")
data, err := ioutil.ReadFile(absPath)
if err != nil {
panic(err)
}
input := string(data)
The input.txt is read as:
a
strong little bird
with a very
big heart
went
to school one day and
forgot his food at
home
However,
re = regexp.MustCompile("\\n")
input = re.ReplaceAllString(input, " ")
turns the text into a mangled mess of:
homeot his food atand
I'm not sure how replacing newlines can mess up so badly to the point where the text inverts itself
I guess that you are running the code using Windows. Observe that if you print out the length of the resulting string, it will show something over 100 characters. The reason is that Windows uses not only newlines (\n) but also carriage returns (\r) - so a newline in Windows is actually \r\n, not \n. To properly filter them out of your string, use:
re := regexp.MustCompile(`\r?\n`)
input = re.ReplaceAllString(input, " ")
The backticks will make sure that you don't need to quote the backslashes in the regular expression. I used the question mark for the carriage return to make sure that your code works on other platforms as well.
I do not think that you need to use regex for such an easy task. This can be achieved with just
absPath, _ := filepath.Abs("../Go/input.txt")
data, _ := ioutil.ReadFile(absPath)
input := string(data)
strings.Replace(input, "\n","",-1)
example of removing \n

(F)Lex checking symbol without "consuming" it

The purpose of this is to concatenate strings (with (f)lex if possible) if they're written consecutively separated only by whitespace.
Strings start and end with "s.
The thing is I used states and while it can concatenate the strings it also consumes the next character/symbol that comes right after the strings.
For example -- "this " "is only " "1 string"id -- this will concatenate the strings ("this is only 1 string") but it will also "consume" the i in id thus destroying one token.
Is there a way to check the next char/symbol without actually "consuming/disposing" (can't really think of a term) it.
\" yy_push_state(X_STRING); yylval.s = new std::string("");
<X_STRING>\" yy_push_state(X_CONC);
<X_STRING>. yylval.s += yytext;
<X_STRING>\n yyerror("newline in string");
<X_CONC>[ ^\n] ;
<X_CONC>\" yy_pop_state();
<X_CONC>. yy_pop_state(); yy_pop_state(); return STRING
Any way to do it?
You can use yyless(0) to cause the current token to be rescanned. Make sure you change start condition, or you'll end up with an endless loop.
By the way, I think your code would be more readable if you switched start conditions with BEGIN rather than using the state stack. In fact, you could easily avoid start conditions, but that would make interpreting escape sequences more complicated. Possibly better would be to just avoid X_CONC by using a rule for \"[[:space:]]*\"

how can delphi 'string' literals be more than 255?

im working on delphi 7 and i was working on a strings, i came across this
For a string of default length, that is, declared simply as string, max size is always 255. A ShortString is never allowed to grow to more than 255 characters.
on delphi strings
once i had to do something like this in my delphi code (that was for a really big query)
var
sMyStringOF256characters : string;
ilength : integer;
begin
sMyStringOF256characters:='ThisStringisofLength256,ThisStringisofLength256,.....'
//length of sMyStringOF256characters is 256
end;
i get this error
[Error] u_home.pas(38): String literals may have at most 255 elements.
but when i try this
var
iCounter : integer;
myExtremlyLongString : string;
begin
myExtremlyLongString:='';
Label1.Caption:='';
for iCounter:=0 to 2500 do
begin
myExtremlyLongString:=myExtremlyLongString+inttostr(iCounter);
Label1.Caption:=myExtremlyLongString;
end;
Label2.Caption:=inttostr(length(myExtremlyLongString));
end;
and the result is
As you can see the length of myExtremlyLongString is 8894 characters.
why did not delphi give any error saying the length is beyond 255 for myExtremlyLongString?
EDIT
i used
SetLength(sMyStringOF256characters,300);
but it doesnt work.
why did not delphi give any error saying the length is beyond 255 for
myExtremlyLongString?
You have your answer a bit down in the text in section Long String (AnsiString).
In current versions of Delphi, the string type is simply an alias for
AnsiString,
So string is not limited to 255 characters but a string literal is. That means that you can build a string that is longer than 255 characters but you can not have a string value in code that is longer than 255 characters. You need to split them if you want that.
sMyString:='ThisStringisofLength255'+'ThisStringisofLength255';
Split it up into:
sMyStringOF256characters :=
'ThisStringis' +
'ofLength256' +
'And ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'ManyManyManyManyManyManyManyManyManyManyManyManyMany' +
'CharactersCharactersCharactersCharactersCharactersCharactersCharactersCharacters';
Back in old DOS/Turbo Pascal days, "strings" were indeed limited to 255 characters. In large part because the 1st byte contained the string length, and a byte can only have a value between 0 and 255.
That is no longer an issue in contemporary versions of Delphi.
"ShortString" is the type for the old DOS/Pascal string type.
"LongString" has been the default string type for a long time (including the Borland Delphi 2006 I currently use for most production work). LongStrings (aka "AnsiStrings") hold 8-bit characters, and are limited only by available memory.
Recent versions of Delphi (Delphi 2009 and higher, including the new Delphi XE2) all now default to multi-byte Unicode "WideString" strings. WideStrings, like AnsiStrings, are also effectively "unlimited" in maximum length.
This article explains in more detail:
http://delphi.about.com/od/beginners/l/aa071800a.htm
The difference is that in your first code example you are putting the string as part of your code - literal string. That has a limitation on how many characters it will allow.
In your second code example you are generating it dynamically and not putting it as one big literal string.
String type in Delphi (unlike shortstring that can only be up to 255) can be as big as your memory.
You could try using the StringBuilder class:
procedure TestStringBuilder;
var
I: Integer;
StringBuilder: TStringBuilder;
begin
StringBuilder := TStringBuilder.Create;
try
for I := 1 to 10 do
begin
StringBuilder.Append('a string ');
StringBuilder.Append(66); //add an integer
StringBuilder.Append(sLineBreak); //add new line
end;
OutputWriteLine('Final string builder length: ' + IntToStr(StringBuilder.Length));
finally
StringBuilder.Free;
end;
end;
If you need realy long string in Delphi, you can load it from other resources like a txt files or just plain text with any extension. Im using it and it works. You can create "like a" array tables using plain text lines numbers. In delphi code, you can do as #arjen van der Spek and others says only.
For me, files with text as var's formated -
sometext:string=
'txt...'+
'txt...'+
'txt...';
are bad for future editing.
pros: you can use any long text.
cons: text code is open, anybody can read it opening file in notepad etc.

Resources