The opposide of string.find() in Lua - lua

The function string.find(char) returns the first occurrence of the pattern in char, but is there any way I can do the reverse: give the position as an int and return the character/number that is there and else returns nil.
I have searched for it if any function exists in the official libraries of the Lua programming language, no results.
I want to make a program which converts a formula of a substance(chemistry) like glucose for example, to the mass in units(u) it has, that is why I need a way to look what is next to the symbol and look if what lies next to the symbol, is a number.

The string.sub function does what you want here.
string.sub (s, i [, j])
Returns the substring of s that starts at i and continues until j; i and j can be negative. If j is absent, then it is assumed to be equal to -1 (which is the same as the string length). In particular, the call string.sub(s,1,j) returns a prefix of s with length j, and string.sub(s, -i) returns a suffix of s with length i.

Related

what is the meaning of source:match("%d*") in lua?

-- Parse speed value as kilometers by hours.
function Measure.parse_value_speed(source)
local n = tonumber(source:match("%d*"))
if n then
if string.match(source, "mph") or string.match(source, "mp/h") then
n = n * miles_to_kilometers
end
return n
end
end
I'm confused with the "*" after %d in the above code. Any comments are greatly appreciated.
It is all in the Lua Reference Manual!
source:match("%d*")
Is syntactic sugar for string.match(source, "%d*")
See https://www.lua.org/manual/5.3/manual.html#3.4.10
string.match(s, pattern [, init]) Looks for the first match of pattern (see ยง6.4.1) in the string s. If it finds one, then match
returns the captures from the pattern; otherwise it returns nil. If
pattern specifies no captures, then the whole match is returned. A
third, optional numeric argument init specifies where to start the
search; its default value is 1 and can be negative.

Lua Pattern Matching - force optional parameters to be filled before it moves on?

I need a pattern that will grab values for two or more parameters of varying length.
I need to convert a scanf format %i to a lua pattern and it is proving very difficult. I don't need to worry about the type of storage that can be passed in with scanf. Just the %i for integer and if they specify a specific link.
Documentation for scanf, if needed, can be found here.
This is what I have so far:
if(scanfLetter == "i" or scanfLetter == "d" or scanfLetter == "u") then
if(specifiedNum == 0)then
newPattern = "([%+%-]?%d+)"
elseif(specifiedNum >= 2)then
newPattern = "([%+%-%d]?%d^".. string.rep("%d?", specifiedNum-2)..")$"
else
newPattern = "(%d)"
end
which basically just checks to see if they passed in a specific number or not (specifiedNum). If it is 0 that means they didn't.
It all works until there are two length specified %is in a row. For example:
%5i%6i
If they enter in 6 or more characters it works fine because match will return two values: the first one consisting of the first 5 numbers and the 6th goes the next value.
The trouble is if there are fewer than 5. In scanf or printf it will not match %5i%6i if there are 5 or fewer numbers, but in my pattern it will still match under string.match and it returns all the values but the last in the first return and the second value get the last number entered.
More specific example so you don't have to type it all out and see it the pattern ends up looking like.
Given:
([%.%+%-%d]?%d[%.%d]?[%.%d]?[%.%d]?)([%.%+%-%d]?%d[%.%d]?[%.%d]?[%.%d]?[%.%d]?)
If 123456789 is passed to it, the match returns 2 values:
`12345` and `6789`
However, if 1234 is passed in, the match returns 2 values:
`123` and `4`
which is incorrect (it should not be a match).
Is what I seek possible?
(Maybe somebody has already written a scanf format to lua patterns converter?)

Might Lua's length operator return a negative index?

The, well, special specification of Lua's length operator made me wonder whether Lua would be "allowed" to return a negative value in a situation like
#{[-5]=1,[-1]=3}
It says:
The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil;
n=-5 and n=-1 would meet this criterion in my example, right?
moreover, if t[1] is nil, n can be zero.
Right, it can be zero, but it's not guaranteed, right?
For a regular array, with non-nil values from 1 to a given n, its length is exactly that n, the index of its last value.
This isn't the case here, so it doesn't apply.
If the array has "holes" (that is, nil values between other non-nil values), then #t can be any of the indices that directly precedes a nil value (that is, it may consider any such nil value as the end of the array).
This is the case here, so again, n=-5 and n=-1 would be valid return values, right?
Can I be entirely certain that Lua always returns 0 for the example table, or any other table containing only negative indices? If (hypothetically) I'd be writing a Lua interpreter and would return either of those values, would I be conforming with the specifications?
Edit
Obviously, the way Lua is implemented, it does not return negative values. I felt the length operator is somewhat underdocumented and I see that Lua 5.2's documentation has changed. It now says:
Unless a __len metamethod is given, the length of a table t is only defined if the table is a sequence, that is, the set of its positive numeric keys is equal to {1..n} for some integer n. In that case, n is its length. Note that a table like
{10, 20, nil, 40}
is not a sequence, because it has the key 4 but does not have the key 3.
So, it now talks about positive numeric keys, that's much clearer. I'm left wiser but not totally happy with the documentation. When it says the "length is only defined if the table is a sequence", it should also state that even if the table is not a sequence a value is returned, but the behavior is undefined. Also, this table looks pretty much like a sequence:
a = setmetatable(
{0},
{
__index = function(t,k)
return k < 10 and k or nil
end
}
)
i = 1
while a[i] do
print(a[i])
i = i+1
end
--[[ prints:
0
2
3
4
5
6
7
8
9
]]
print(#a)
-- prints: 1
However, this is becoming nitpicking as it's pretty clear that it wouldn't make sense to take into account what mess __index might make. And Stackoverflow is certainly not the place to complain about documentation that could be more precise.
As you have noted, the specification of the length operator has changed between 5.1 and 5.2.
Can I be entirely certain that Lua always returns 0 for the example table, or any other table containing only negative indices?
You can for the current reference implementation, which ensures that for ilen defined
function ilen (xs)
local i=0
while xs[i+1] do i=i+1 end
return i
end
we always have #xs >= ilen(xs) - see the definition of luaH_getn in the ltable.c source. But the specification now deliberately does not promise this behaviour: a conformant implementation can return nil or raise an exception for attempts to find the length of tables that are not sequences.
From the text in reference link. The answer is NO.
I think your confusing the fact that if a NIL is found then the length of the table is deemed to be position the NIL was found -1.
Therefore if t(1) is NIL then 1 - 1 = 0 so the table length is 0.
If the length of a table was 5 then the next position or t(6) IS or WOULD BE NIL
The length of a table t is defined to be any integer index n such that t[n] is not nil and t[n+1] is nil; moreover, if t[1] is nil, n can be zero.

Read numbers following a keyword into an array in Fortran 90 from a text file

I have many text files of this format
....
<snip>
'FOP' 0.19 1 24 1 25 7 8 /
'FOP' 0.18 1 24 1 25 9 11 /
/
TURX
560231
300244
70029
200250
645257
800191
900333
600334
770291
300335
220287
110262 /
SUBTRACT
'TURX' 'TURY'/
</snip>
......
where the portions I snipped off contain other various data in various formats. The file format is inconsistent (machine generated), the only thing one is assured of is the keyword TURX which may appear more than once. If it appears alone on one line, then the next few lines will contain numbers that I need to fetch into an array. The last number will have a space then a forward slash (/). I can then use this array in other operations afterwards.
How do I "search" or parse a file of unknown format in fortran, and how do I get a loop to fetch the rest of the data, please? I am really new to this and I HAVE to use fortran. Thanks.
Fortran 95 / 2003 have a lot of string and file handling features that make this easier.
For example, this code fragment to process a file of unknown length:
use iso_fortran_env
character (len=100) :: line
integer :: ReadCode
ReadLoop: do
read (75, '(A)', iostat=ReadCode ) line
if ( ReadCode /= 0 ) then
if ( ReadCode == iostat_end ) then
exit ReadLoop
else
write ( *, '( / "Error reading file: ", I0 )' ) ReadCode
stop
end if
end if
! code to process the line ....
end do ReadLoop
Then the "process the line" code can contain several sections depending on a logical variable "Have_TURX". If Have_TRUX is false you are "seeking" ... test whether the line contains "TURX". You could use a plain "==" if TURX is always at the start of the string, or for more generality you could use the intrinsic function "index" to test whether the string "line" contains TURX.
Once the program is in the mode Have_TRUX is true, then you use "internal I/O" to read the numeric value from the string. Since the integers have varying lengths and are left-justified, the easiest way is to use "list-directed I/O": combining these:
read (line, *) integer_variable
Then you could use the intrinsic function "index" again to test whether the string also contains a slash, in which case you change Have_TRUX to false and end reading mode.
If you need to put the numbers into an array, it might be necessary to read the file twice, or to backspace the file, because you will have to allocate the array, and you can't do that until you know the size of the array. Or you could pop the numbers into a linked list, then when you hit the slash allocate the array and fill it from the linked list. Or if there is a known maximum number of values you could use a temporary array, then transfer the numbers to an allocatable output array. This is assuming that you want the output argument of the subroutine be an allocatable array of the correct length, and the it returns one group of numbers per call:
integer, dimension (:), allocatable, intent (out) :: numbers
allocate (numbers (1: HowMany) )
P.S. There is a brief summary of the language features at http://en.wikipedia.org/wiki/Fortran_95_language_features and the gfortran manual has a summary of the intrinsic procedures, from which you can see what built in functions are available for string handling.
I'll give you a nudge in the right direction so that you can finish your project.
Some basics:
Do/While as you'll need some sort of loop
structure to loop through the file
and then over the numbers. There's
no for loop in Fortran, so use this
type.
Read
to read the strings.
To start you need something like this:
program readlines
implicit none
character (len=30) :: rdline
integer,dimension(1000) :: array
! This sets up a character array with 30 positions and an integer array with 1000
!
open(18,file='fileread.txt')
do
read(18,*) rdline
if (trim(rdline).eq.'TURX') exit !loop until the trimmed off portion matches TURX
end do
See this thread for way to turn your strings into integers.
Final edit: Looks like MSB has got most of what I just found out. The iostat argument of the read is the key to it. See this site for a sample program.
Here was my final way around it.
PROGRAM fetchnumbers
implicit none
character (len=50) ::line, numdata
logical ::is_numeric
integer ::I,iost,iost2,counter=0,number
integer, parameter :: long = selected_int_kind(10)
integer, dimension(1000)::numbers !Can the number of numbers be up to 1000?
open(20,file='inputfile.txt') !assuming file is in the same location as program
ReadLoop: do
read(20,*,iostat=iost) line !read data line by line
if (iost .LT. 0) exit !end of file reached before TURX was found
if (len_trim(line)==0) cycle ReadLoop !ignore empty lines
if (index(line, 'TURX').EQ.1) then !prepare to begin capturing
GetNumbers: do
read(20, *,iostat=iost2)numdata !read in the numbers one by one
if (.NOT.is_numeric(numdata)) exit !no more numbers to read
if (iost2 .LT. 0) exit !end of file reached while fetching numbers
read (numdata,*) number !read string value into a number
counter = counter + 1
Storeloop: do I =1,counter
if (I<counter) cycle StoreLoop
numbers(counter)=number !storing data into array
end do StoreLoop
end do GetNumbers
end if
end do ReadLoop
write(*,*) "Numbers are:"
do I=1,counter
write(*,'(I14)') numbers(I)
end do
END PROGRAM fetchnumbers
FUNCTION is_numeric(string)
IMPLICIT NONE
CHARACTER(len=*), INTENT(IN) :: string
LOGICAL :: is_numeric
REAL :: x
INTEGER :: e
is_numeric = .FALSE.
READ(string,*,IOSTAT=e) x
IF (e == 0) is_numeric = .TRUE.
END FUNCTION is_numeric

Why are there parentheses and dots after an array's name instead of brackets?

When accessing an element in an array the square brackets are used like so:
{'X is an int and Numbers is an int array'}
X := Numbers[8];
However, While reading others' code I sometimes find the following syntax:
{'PBox , SBox1 , SBox2 are arrays of int , And X,Y are ints'}
Result := Result or PBox(.SBox1[X] or SBox2[Y].);
What does it mean to have parentheses after the array's name, as in PBox(someNumber)? Is this another way to access an array element?
What does the "." before SBox1 and after SBox2 mean? Both SBox1 and SBox2 are arrays. The code compiles without error but I don't know what those dots are for.
Yes, now I see what you do.
In fact, (. and .) are merely alternative ways (but very uncommon!) of writing [ and ] in Delphi.
If PBox is an array, then PBox[a] (or, equivalently, PBox(.a.)) would require a to be an integer, right? And if SBox1[x] and SBox2[Y] are integers, so is the bitwise or of them. (Bitwise or is an operation that takes two integers and returns a new integer.) Hence, PBox(.SBox1[X] or SBox2[Y].) is the (SBox1[X] or SBox2[Y])th element in the array PBox, that is, an integer. So it makes sense to compute the bitwise or between Result and this integer, which is what is done:
Result := Result or PBox(.SBox1[X] or SBox2[Y].);

Resources