find the nth value in a value in structured text - st

I have experience of VB and c# but not ST. Im trying to find the value of the nth digit in a value. ie 654321 the nth value when n = 3 should return 4. Is it possible to do this in ST?

I suggest to convert the number to STRING and then you can find the nth character from the string. Of course, you didn't tell that if your number 654321 is a string or number value, but it doesn't really matter.
The following code takes the 3rd character from the left. If you need to get the digit from right, you can edit the code using LEN() etc. functions.
VAR
TestNumber : DINT;
TestString : STRING;
NthDigitAsString : STRING(1);
NthDigit : BYTE;
END_VAR
TestNumber := 654321;
//Convert to string
TestString := DINT_TO_STRING(TestNumber);
//Find the 3rd character (counting from from left)
NthDigitAsString := MID(TestString, 1, 3);
//Convert the character to number (if necessary)
NthDigit := STRING_TO_BYTE(NthDigitAsString);
That is of course a long version. Find the one-liner below:
NthDigit := STRING_TO_BYTE(MID(DINT_TO_STRING(654321), 1, 3));

Related

How to split data every n-th character and make it into array in crystal report

i want to split data to make it into array. so given for example: 12345678
i want to get string array like this => ["234","678"]
is it possible in crystal report?
Yes, it is possible. But the requirements are not clear.
Data type of input (string or Number?)
Logic: discard 1st character? Then, groups of 3 skipping the 4th character?
Here is formula code that takes "12345678" and returns "^234^678":
local stringvar myString := "12345678";
local stringvar myDelimitedString := "";
local numbervar StringLength := Len(myString);
local numbervar i;
For i := 1 to StringLength step 4 do
myDelimitedString := myDelimitedString + "^" + MID(myString, i+ 1, 3);
myDelimitedString;

Twincat 3.0 How to convert string to ASCII code and vice-versa?

Is there any function block which allows conversion of string to ASCII code and vice versa in TwinCAT?
I found this function f_ToCHR, but it only converts one character at a time and for converting the whole string, I would need to put it in a for loop, which would not be optimal.
Is there any function that could do the whole string conversion, not character by character?
You could create a UNION with a string and a byte array. This will put them in the same memory space, and since a string is simply a series of ASCII bytes, the individual character values will end up in each array element.
TYPE testUnion
UNION
stTest : STRING;
arTest : ARRAY[0..79] OF BYTE;
END_UNION
END_TYPE

Converting numbers into timestamps (inserting colons at specific places)

I'm using AutoHotkey for this as the code is the most understandable to me. So I have a document with numbers and text, for example like this
120344 text text text
234000 text text
and the desired output is
12:03:44 text text text
23:40:00 text text
I'm sure StrReplace can be used to insert the colons in, but I'm not sure how to specify the position of the colons or ask AHK to 'find' specific strings of 6 digit numbers. Before, I would have highlighted the text I want to apply StrReplace to and then press a hotkey, but I was wondering if there is a more efficient way to do this that doesn't need my interaction. Even just pointing to the relevant functions I would need to look into to do this would be helpful! Thanks so much, I'm still very new to programming.
hfontanez's answer was very helpful in figuring out that for this problem, I had to use a loop and substring function. I'm sure there are much less messy ways to write this code, but this is the final version of what worked for my purposes:
Loop, read, C:\[location of input file]
{
{ If A_LoopReadLine = ;
Continue ; this part is to ignore the blank lines in the file
}
{
one := A_LoopReadLine
x := SubStr(one, 1, 2)
y := SubStr(one, 3, 2)
z := SubStr(one, 5)
two := x . ":" . y . ":" . z
FileAppend, %two%`r`n, C:\[location of output file]
}
}
return
Assuming that the "timestamp" component is always 6 characters long and always at the beginning of the string, this solution should work just fine.
String test = "012345 test test test";
test = test.substring(0, 2) + ":" + test.substring(2, 4) + ":" + test.substring(4, test.length());
This outputs 01:23:45 test test test
Why? Because you are temporarily creating a String object that it's two characters long and then you insert the colon before taking the next pair. Lastly, you append the rest of the String and assign it to whichever String variable you want. Remember, the substring method doesn't modify the String object you are calling the method on. This method returns a "new" String object. Therefore, the variable test is unmodified until the assignment operation kicks in at the end.
Alternatively, you can use a StringBuilder and append each component like this:
StringBuilder sbuff = new StringBuilder();
sbuff.append(test.substring(0,2));
sbuff.append(":");
sbuff.append(test.substring(2,4));
sbuff.append(":");
sbuff.append(test.substring(4,test.length()));
test = sbuff.toString();
You could also use a "fancy" loop to do this, but I think for something this simple, looping is just overkill. Oh, I almost forgot, this should work with both of your test strings because after the last colon insert, the code takes the substring from index position 4 all the way to the end of the string indiscriminately.

Syntax for Returning One Character of String by Index

I am attempting to compare one character of a string to see if it is my delimiter character. However, when I execute the following code the value that gets placed in the variable valstring is a number that represents the byte that was converted to a string and not a character itself. For Example the value may be the string '58'.
Through my testing in CoDeSys using the debugging features I know that the string sReadLine contains a valid string of characters. I'm just not sure of the syntax to single only one of them out; the sReadLine[valPos + i] part is what I don't understand.
sReadLine : STRING;
valstring : STRING;
i : INT;
valPos : INT;
FOR i := 0 TO 20 DO
IF BYTE_TO_STRING(sReadLine[valPos + i]) = '"' THEN
EXIT;
END_IF
valstring := CONCAT(STR1 := valstring, STR2 := BYTE_TO_STRING(sReadLine[valPos + i]));
END_FOR
I think you have multiple choises.
1) Use built-in string functions instead. You can use MID function get get part of a string. So in your case something like "get one character from valPos + 1 from sReadLine.
FOR i := 0 TO 20 DO
IF MID(sReadLine, 1, valPos + i) = '"' THEN
EXIT;
END_IF
valstring := CONCAT(STR1 := valstring, STR2 := MID(sReadLine, 1, valPos + i));
END_FOR
2) Convert the ASCII byte to string. In TwinCAT systems, there is a function F_ToCHR. It takes a ASCII byte in and returns the character as string. I can't find something like that for Codesys, but i'm sure there would be a solution in some library. So please note that this won't work in Codesys without modifications:
FOR i := 0 TO 20 DO
IF F_ToCHR(sReadLine[valPos + i]) = '"' THEN
EXIT;
END_IF
valstring := CONCAT(STR1 := valstring, STR2 := F_ToCHR(sReadLine[valPos + i]));
END_FOR
3) The OSCAT library seems to have a CHR_TO_STRING function. You could use this instead of F_ToCHR in step 2.
4) You can use pointers to copy the ASCII byte to a string array (MemCpy) and add a string end character. This needs some knowledge of pointers etc. See Codesys forum for some example.
5) You can write a helper function similar to step 2 youself. Check the example from Codesys forums. That example doesn't include all characters so it needs to be updated. It's not quite elegant.
When you convert a byte to a string, what is beeing converted is the digital representation of the byte.
This means you are interpreting that byte as an ascii character (The ascii decimal value of : is 58).
So if you want to Concat chars instead of their ascii decimal representation, you need another function:
valstring := CONCAT(STR1 := valstring, STR2 := F_ToCHR(sReadLine[valPos + i]));
EDIT:
As Quirzo, I couldn't find a similar F_ToCHR function for Codesys, but you could easily build one yourself.
For example:
Declaration Part:
FUNCTION F_ASCII_TO_STRING : STRING
VAR_INPUT
input : BYTE;
END_VAR
VAR
ascii : ARRAY[0..255] OF STRING(1):=
[
33(' '),'!','"','#',
'$$' ,'%' ,'&' ,'ยด',
'(' ,')' ,'*' ,'+' ,
',' ,'-' ,'.' ,'/' ,
'0' ,'1' ,'2' ,'3' ,
'4' ,'5' ,'6' ,'7' ,
'8' ,'9' ,':' ,';' ,
'<' ,'=' ,'>' ,'?' ,
'#' ,'A' ,'B' ,'C' ,
'D' ,'E' ,'F' ,'G' ,
'H' ,'I' ,'J' ,'K' ,
'L' ,'M' ,'N' ,'O' ,
'P' ,'Q' ,'R' ,'S' ,
'T' ,'U' ,'V' ,'W' ,
'X' ,'Y' ,'Z' ,'[' ,
'\' ,']' ,'^' ,'_' ,
'`' ,'a' ,'b' ,'c' ,
'd' ,'e' ,'f' ,'g' ,
'h' ,'i' ,'j' ,'k' ,
'l' ,'m' ,'n' ,'o' ,
'p' ,'q' ,'r' ,'s' ,
't' ,'u' ,'v' ,'w' ,
'x' ,'y' ,'z' ,'{' ,
'|' ,'}' ,'~'
];
END_VAR
Implementation part:
F_ASCII_TO_STRING := ascii[input];
As Sergey said, this might not be an optimal solution to your problem. It seems like you want to extract the longest substring not containing any character " from initial input sReadLine to valstring, starting from position valPos.
In your implementation, for each valid input character, CONCAT() needs to search for the end of valstring, before appending only 1 character to it.
You should rather decompose your problem and use two standard functions to be optimal:
FIND() --> to get the position of the next character " (or to know if there is none),
MID() --> to create a string from initial position up to before the first character " (or the end of the input string).
That way, there remains only 2 loops; each one is hidden in these functions.

Remove last n characters of string after the dot with Autohotkey

I am using Autohotkey.
I have a string that looks like this S523.WW.E.SIMA. I want to remove the last few characters of the string after the dot (including the dot itself). So, after the removal, the string will look like S523.WW.E.
This may look like a simple question but I just cannot figure out using the available string functions in Autohotkey. How can this be done using Autohotkey? Thank you very much.
Example 1 (last index of)
string := "S523.WW.E.SIMA"
LastDotPos := InStr(string,".",0,0) ; get position of last occurrence of "."
result := SubStr(string,1,LastDotPos-1) ; get substring from start to last dot
MsgBox %result% ; display result
See InStr
See SubStr
Example 2 (StrSplit)
; Split it into the dot-separated parts,
; then join them again excluding the last part
parts := StrSplit(string, ".")
result := ""
Loop % parts.MaxIndex() - 1
{
if(StrLen(result)) {
result .= "."
}
result .= parts[A_Index]
}
Example 3 (RegExMatch)
; Extract everything up until the last dot
RegExMatch(string, "(.*)\.", result)
msgbox % result1
Example 4 (RegExReplace)
; RegExReplace to remove everything, starting with the last dot
result := RegExReplace(string, "\.[^\.]+$", "")