From: Bart Vandewoestyne on
I have config files with lines that look as follows:

on 0.2 0.2 0.02 0.02 0.01 0.01 pulse 5.0e8 100e3

The number of spaces between items is arbitrary, and the number
formatting is also arbitrarily chosen by the user. The number of
numbers after 'pulse' can vary.

I read this as:

character(len=100) :: pointsource_string
...
read(unit=my_unit, fmt="(A)", iostat=ios) pointsource_string

But now I want to split pointsource_string in two, namely so that
the two resulting strings are:

on 0.2 0.2 0.02 0.02 0.01 0.01 pulse

and

5.0e8 100e3


I have looked into my Fortran 95/2003 explained handbook,
searching for a way to skip 7 'whitespace areas'... but i could
not come up with an elegant method to split the string at the
point where I want to split.

Any suggestions on how to do this?

Thanks,
Bart

--
"Share what you know. Learn what you don't."
From: dpb on
Bart Vandewoestyne wrote:
> I have config files with lines that look as follows:
>
> on 0.2 0.2 0.02 0.02 0.01 0.01 pulse 5.0e8 100e3
>
> The number of spaces between items is arbitrary, and the number
> formatting is also arbitrarily chosen by the user. The number of
> numbers after 'pulse' can vary.
>
> I read this as:
>
> character(len=100) :: pointsource_string
> ...
> read(unit=my_unit, fmt="(A)", iostat=ios) pointsource_string
>
> But now I want to split pointsource_string in two, namely so that
> the two resulting strings are:
>
> on 0.2 0.2 0.02 0.02 0.01 0.01 pulse
>
> and
>
> 5.0e8 100e3
>
....

> Any suggestions on how to do this?

idx = index(ps_string, 'pulse', back=.true.) + len('pulse')+1
left_str = ps_string(1:idx-1)
rite_str = ps_string(idx:len_trim(ps_string)

--
From: Bart Vandewoestyne on
On 2009-10-07, dpb <none(a)non.net> wrote:
>
>> Any suggestions on how to do this?
>
> idx = index(ps_string, 'pulse', back=.true.) + len('pulse')+1
> left_str = ps_string(1:idx-1)
> rite_str = ps_string(idx:len_trim(ps_string)

Sorry... i forgot to mention that the text 'pulse' can also be
something else and with a different length... so the above trick
doesn't work for me.

Regards,
Bart

--
"Share what you know. Learn what you don't."
From: Richard Maine on
Bart Vandewoestyne <MyFirstName.MyLastName(a)telenet.be> wrote:

> I have looked into my Fortran 95/2003 explained handbook,
> searching for a way to skip 7 'whitespace areas'... but i could
> not come up with an elegant method to split the string at the
> point where I want to split.
>
> Any suggestions on how to do this?

There isn't anything "magic". Just search for non-whitspace and then
search for whitespace. Loop the appropriate number of times. See the
index, scan, and verify intrinsics.

If I were doing it, I'd use my find_field utility subroutine, copied
below. This does other stuff as well. You don't need anything within an
order of magnitude this long. It isn't that hard a job. But this is a
subroutine that I already have and is suitable. I think most people who
end up doing much in the way of character processing develop a personal
collection of utility routines. It sure beats doing everything from
scratch every time. (I pulled this from a module that includes a bunch
of others as well).

subroutine find_field (string, field, position, delims, delim, found)

!-- Find a delimitted field in a string.
!-- 15 Nov 90, Richard Maine.

!-------------------- interface.
character*(*), intent(in) :: string !-- The string input.
character*(*), intent(out) :: field
!-- The returned field. Blank if no field found.
integer, optional, intent(inout) :: position
!-- On entry, the starting position for searching for the
field.
!-- Default is 1 if the argument is not present.
!-- On exit, the starting position of the next field or
!-- len(string)+1 if there is no following field.
character*(*), optional, intent(in) :: delims
!-- String containing the characters to be accepted as
delimitters.
!-- If this includes a blank character, then leading blanks are
!-- removed from the returned field and the end delimitter may
!-- optionally be preceeded by blanks. If this argument is
!-- not present, the default delimitter set is a blank.
character*(*), optional, intent(out) :: delim
!-- Returns the actual delimitter that terminated the field.
!-- Returns char(0) if the field was terminated by the end of
!-- the string or if no field was found.
!-- If blank is in delimitters and the field was terminated
!-- by one or more blanks, followed by a non-blank delimitter,
!-- the non-blank delimitter is returned.
logical, optional, intent(out) :: found
!-- True if a field was found.

!-------------------- local.
character :: delimitter*1
integer :: pos, field_start, field_end, i
logical :: trim_blanks

!-------------------- executable code.

field = ''
delimitter = char(0)
pos = 1
if (present(found)) found = .false.
if (present(position)) pos = position
if (pos > len(string)) goto 9000
if (pos < 1) call error_halt('Illegal position in find_field')

!-- Skip leading blanks if blank is a delimitter.
field_start = pos
trim_blanks = .true.
if (present(delims)) trim_blanks = index(delims,' ') /= 0
if (trim_blanks) then
i = verify(string(pos:),' ')
if (i == 0) then
pos = len(string) + 1
goto 9000
end if
field_start = pos + i - 1
end if
if (present(found)) found = .true.

!-- Find the end of the field.
if (present(delims)) then
i = scan(string(field_start:), delims)
else
i = scan(string(field_start:), ' ')
end if
if (i == 0) then
field_end = len(string)
delimitter = char(0)
pos = field_end + 1
else
field_end = field_start + i - 2
delimitter = string(field_end+1:field_end+1)
pos = field_end + 2
end if

!-- Return the field.
field = string(field_start:field_end)

!-- Skip trailing blanks if blank is a delimitter.
if (trim_blanks) then
i = verify(string(field_end+1:), ' ')
if (i == 0) then
pos = len(string) + 1
goto 9000
end if
pos = field_end + i

!-- If the first non-blank character is a delimitter,
!-- skip blanks after it.
i = 0
if (present(delims)) i = index(delims, string(pos:pos))
if (i /= 0) then
delimitter = string(pos:pos)
pos = pos + 1
i = verify(string(pos:), ' ')
if (i == 0) then
pos = len(string) + 1
else
pos = pos + i - 1
end if
end if
end if

!---------- Normal exit.
9000 continue
if (present(delim)) delim = delimitter
if (present(position)) position = pos
return
end subroutine find_field


--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain
From: The Star King on
On Oct 7, 4:26 pm, Bart Vandewoestyne
<MyFirstName.MyLastN...(a)telenet.be> wrote:
> On 2009-10-07, dpb <n...(a)non.net> wrote:
>
>
>
> >> Any suggestions on how to do this?
>
> > idx = index(ps_string, 'pulse', back=.true.) + len('pulse')+1
> > left_str = ps_string(1:idx-1)
> > rite_str = ps_string(idx:len_trim(ps_string)
>
> Sorry... i forgot to mention that the text 'pulse' can also be
> something else and with a different length... so the above trick
> doesn't work for me.
>
> Regards,
> Bart
>
> --
>         "Share what you know.  Learn what you don't."

I suggest

character(30) :: data(10)
integer i

read (pointsource_string,*) (data(i),i=1,10)

then data(1)=on, data(2)=0.2 etc (NB data(i) are all strings)

you can then recombine the strings as you want

lefts=trim(data(1))//trim(data(2))//... etc
rights=trim(data(9))//trim(data(10))

(this will get rid of the white space between blocks of text)

to convert to a number

real f

read(data(2),*) f