IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Fortran Discussion :

lire chaine de caractères à longueur variable


Sujet :

Fortran

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2010
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2010
    Messages : 31
    Points : 14
    Points
    14
    Par défaut lire chaine de caractères à longueur variable
    bonsoir,

    J'essaye de lire des lignes dans un fichier à longueur variables, comme ceci :
    avec le premier chiffre qui donne le nombre de chiffres à suivre...

    j'ai crée un vecteur allocatable, mais il faut évidemment y affecter une longueur, que je ne connais une fois avoir lu la ligne...

    j'ai trouvé une solution en organisant mon fichier comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    2
    1    2
    2
    2    3
    3
    1    2    3
    je lis une ligne qui me donne la longueur de la prochaine ligne et donc du vecteur à allouer, mais j'aimerais vraiment trouver une solution pour la 1ère organisation.

    Merci de votre aide,
    Thomas

  2. #2
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2013
    Messages
    388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2013
    Messages : 388
    Points : 692
    Points
    692
    Par défaut
    Salut.
    J'avais développé jadis un module gérant les listes chainées pour traiter ces problèmes.
    Je le poste tel quel ainsi qu'un exemple.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    module list_string
    ! ----------------------------------------------------------------------
    ! Public :
    ! split         (line, delim)           -> list     29.07.2013
    ! remove        (a_list)                subroutine  29.07.2013
    ! get           (a_list, idx)           -> string   29.07.2013
    ! append        (a_list, a_string)      subroutine  01.08.2013
    ! pop           (a_list, idx)           -> string   01.08.2013
    ! display       (a_list)                subroutine  01.08.2013
    ! put           (a_list, idx, a_string) subroutine  01.08.2013
    ! insert        (a_list, idx, a_string) subroutine  02.08.2013
    ! list_s2array  (a_list)                -> array    03.08.2013
    !
    ! Private :
    ! libere        (ptr)                   subroutine  29.07.2013
    ! out_of_range  (a_list,idx)            -> logical  01.08.2013
    ! not_defined   (ptr)                   -> logical  01.08.2013
    !
    ! Améliorations :
    ! contains      (a_list, a_string)      -> logical  plus tard
    ! len           (a_list)                -> integer
    !
    ! Rem : pb alloc. dyn. des chaines avec version de gfortran (gcc 4.7.3)
    !         character(len=:), allocatable :: value
    !                                               1
    ! Error: Deferred-length character component 'value' at (1) is not yet supported
    !
    ! ----------------------------------------------------------------------
        implicit none
        integer, parameter :: NBCHAR = 64
     
        type word
            character(len=NBCHAR) :: value
            type(word), pointer   :: p_next => null()
        end type word
     
        type list_s
            type(word), pointer :: p_first => null()
            integer :: size
        end type list_s
     
        private :: libere, out_of_range, not_defined
     
    contains
     
        function split (line, delim) result (a_list)
            character(len=*), intent(in) :: line
            character(len=*), intent(in) :: delim
            type(list_s) :: a_list
            integer :: idx1         ! position 1er charact. après delim
            integer :: idx2         ! position du delim finissant le mot
            integer :: step         ! nb char de fin du delim au debut nv delim
            integer :: l_delim
            l_delim = len(delim)
            idx1 = 1 ; idx2 =  0 ; a_list%size = 0
            do
                step = index(line(idx1:),delim) - 1
                if (step==-1) exit
                idx2 = idx1 + step
                call append (a_list, line(idx1:idx2-1))
                idx1 = idx2 + l_delim
            enddo
            if (idx2>0) then
                idx1 = idx2 + l_delim
                idx2 = len_trim(line)
                call append (a_list, line(idx1:idx2))
            else
                call append (a_list, trim(line))
            endif
        end function split
     
        subroutine append (a_list, txt)
            type(list_s), intent(inout) :: a_list
            character(len=*), intent(in) :: txt
            type(word), pointer :: p_prec => null()
            type(word), pointer :: p_curr => null()
     
            if (.not. associated(a_list%p_first)) then
                allocate(a_list%p_first)
                p_curr => a_list%p_first
                a_list%size = 1
            else
                p_prec => a_list%p_first
                p_curr => p_prec%p_next
                do
                    if (.not. associated(p_curr)) exit
                    p_prec => p_curr
                    p_curr => p_curr%p_next
                enddo
                allocate(p_curr)
                p_prec%p_next => p_curr
                a_list%size = a_list%size + 1
            endif
            p_curr%value = txt
        end subroutine append
     
        subroutine remove (a_list)
            type(list_s), intent(inout) :: a_list
            if (.not. associated(a_list%p_first)) then
                print '(/"--- Empty list"/)'
            else
                call libere (a_list%p_first)
                a_list%size = 0
            endif
        end subroutine remove
     
        recursive subroutine libere (ptr)
            type(word), pointer :: ptr
            if (associated(ptr%p_next)) call libere(ptr%p_next)
            deallocate(ptr)
        end subroutine libere
     
        function get (a_list, idx) result (item)
            type(list_s), intent(in) :: a_list
            integer, intent(in) :: idx
            character(len=NBCHAR) :: item
            integer :: i
            type(word), pointer :: p_curr => null()
            item = ""
            if (out_of_range (a_list,idx))      return
            if (not_defined (a_list%p_first))   return
            p_curr => a_list%p_first
            do i = 1, idx-1
                p_curr => p_curr%p_next
                if (not_defined (p_curr)) return
            enddo
            item = p_curr%value
        end function get
     
        subroutine display (a_list)
            type(list_s), intent(inout) :: a_list
            character(len=*), parameter :: my_fmt = '(i3,x,"''",a,"''")'
            type(word), pointer :: p_curr => null()
            integer :: i
            p_curr => a_list%p_first ; i = 0
            do
                if (.not. associated(p_curr)) exit
                i = i + 1
                print my_fmt, i, trim(p_curr%value)
                p_curr => p_curr%p_next
            enddo
            print *
        end subroutine display
     
        function pop (a_list, idx) result (item)
            type(list_s), intent(inout) :: a_list
            integer, intent(in) :: idx
            character(len=NBCHAR) :: item
            integer :: i
            type(word), pointer :: p_prec => null()     ! item idx-1
            type(word), pointer :: p_curr => null()     ! item idx
            type(word), pointer :: p_next => null()     ! item idx+1
     
            item = ""
            if (out_of_range (a_list,idx))      return
            if (not_defined (a_list%p_first))   return
            if (idx==1) then
                p_prec => null()
                p_curr => a_list%p_first
            else
                p_prec => a_list%p_first
                do i = 1, idx-2
                    p_prec => p_prec%p_next
                    if (not_defined (p_prec)) return
                enddo
                p_curr => p_prec%p_next
            endif
            item = p_curr%value
            if (idx==a_list%size) then
                p_next => null()
            else
                p_next => p_curr%p_next
            endif
            if (idx==1) then
                a_list%p_first => p_next
            else
                p_prec%p_next => p_next
            endif
            deallocate(p_curr)
            a_list%size = a_list%size - 1
        end function pop
     
        subroutine put (a_list, idx, txt)
            type(list_s), intent(inout) :: a_list
            integer, intent(in) :: idx
            character(len=*), intent(in) :: txt
            type(word), pointer :: p_curr => null()
            integer :: i
     
            if (out_of_range (a_list,idx))      return
            if (not_defined (a_list%p_first))   return
            p_curr => a_list%p_first
            do i = 1, idx-1
                p_curr => p_curr%p_next
                if (not_defined (p_curr)) return
            enddo
            p_curr%value = trim(txt)
        end subroutine put
     
        function out_of_range (a_list,idx)
            type(list_s), intent(in) :: a_list
            integer, intent(in) :: idx
            logical out_of_range
            if (idx<=0 .or. idx>a_list%size) then
                print '(/,"--- Error : index",x,i3,x,"out of range",/)', idx
                out_of_range = .true.
            else
                out_of_range = .false.
            endif
        end function out_of_range
     
        function not_defined (ptr)
            type(word), pointer, intent(in) :: ptr
            logical not_defined
            if (.not. associated(ptr)) then
                print '(/,"--- Error : pointer not associated",/)'
                not_defined = .true.
            else
                not_defined = .false.
            endif
        end function not_defined
     
        subroutine insert (a_list, idx, txt)
            type(list_s), intent(inout) :: a_list
            integer, intent(in) :: idx
            character(len=*), intent(in) :: txt
            type(word), pointer :: p_prec => null()
            type(word), pointer :: p_curr => null()
            type(word), pointer :: p_next => null()
            integer :: i
     
            if (out_of_range (a_list,idx))      return
            if (not_defined (a_list%p_first))   return
     
            allocate(p_curr)
            a_list%size = a_list%size + 1
            p_curr%value = trim(txt)
     
            if (idx==1) then
                p_prec => null()
                p_next => a_list%p_first
                a_list%p_first => p_curr
            else
                p_prec => a_list%p_first
                do i = 1, idx-2
                    p_prec => p_prec%p_next
                    if (not_defined (p_prec)) return
                enddo
                p_next => p_prec%p_next
                p_prec%p_next => p_curr
            endif
            p_curr%p_next => p_next
     
        end subroutine insert
     
        function list_s2array (a_list) result (arr)
            type(list_s), intent(in) :: a_list
            character(len=NBCHAR), allocatable :: arr(:)
            type(word), pointer :: p_curr => null()
            integer :: i
            allocate(arr(a_list%size))
            if (not_defined (a_list%p_first)) return
            p_curr => a_list%p_first ; i = 0
            do
                if (.not. associated(p_curr)) exit
                i = i + 1
                arr(i) = p_curr%value
                p_curr => p_curr%p_next
            enddo
        end function list_s2array
     
    end module list_string
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    program test_list_module
        use list_string
        implicit none
        type(list_s) :: l1
     
        l1 = split("; ;;-6839;01/01/2009;01:33:28;;01/01/2009;01:00:00;0;", delim=";")
        call display(l1)
     
        call append(l1, "toto")
        call display(l1)
     
        call remove(l1)
        call append(l1, "le bel oranger")
        call append(l1, "edelweiss")
        call append(l1, "abracadabra")
        call display(l1)
     
        print '(a)', pop(l1, idx=2)
        call display(l1)
     
        call put(l1, idx=3, txt="salusava")
        call display(l1)
     
        call insert(l1, idx=1, txt="gloubiboulga")
        call display(l1)
     
        call remove(l1)
     
    end program test_list_module
    Edit : pour éviter de galérer tout seul avec mon programme, voici un exemple plus proche de ce que tu attends :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    program demo_split
        use list_string
        implicit none
        character(len=*), parameter :: filename = "files/nb_var_var.txt"
        character(len=512) :: line
        character(len=NBCHAR) :: item
        integer :: io, i, k
        type(list_s) :: items
     
        open(unit=11, file=filename, status="old", action="read")
        do
            read(11, '(a)', iostat=io) line
            if (io /= 0) exit
            items = split(trim(line), delim=" ")
            item = get(items, idx=1)
            print '(a,x,a)', 'Nb variables :', trim(item)
            do i = 2, items%size
                item = get(items, idx=i)
                if (trim(item) == '') cycle
                read(item, *) k
                print '(i4)', k
            enddo
            call remove(items)
        enddo
        close(11)
     
    end program demo_split

  3. #3
    Membre régulier
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Août 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2008
    Messages : 57
    Points : 91
    Points
    91
    Par défaut
    J'avais rencontré e problème, et proposé une solution plus "artisanale" que celle de __dardanos__.

    L'idée était de lire la ligne, la stocker dans une chaîne de caractères de taille suffisante (il y a donc une limite à la taille de ligne, mais ce n'est en général pas un très gros problème), puis de l'analyser et stocker les données.

    De mémoire, ça donnait quelque chose comme ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    REAL(8), ALLOCATABLE:: stock(:)
    INTEGER::i,debut,longueur
    CHARACTER(200)::dummy
     
    OPEN(10,FILE='blabla')
     
    READ(10,'(A)') dummy ! le '(A)' évite de s'arrêter au premier espace
     
    longueur=1
    DO i=1,len_trim(dummy)
       IF (dummy(i:i)==' ') THEN ! il y a un espace entre les parenthèses; il faut être un peu plus subtil si il y a plusieurs espaces de séparation
          longueur=longueur+1     
       ENDIF
    ENDDO
    ! A ce stade, on peut allouer le vecteur
    ALLOCATE(stock(longueur))
    ! Et on relit la chaîne pour avoir les valeurs
      READ(dummy,*) stock
    En espérant que ça aide

  4. #4
    Membre régulier
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Août 2008
    Messages
    57
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2008
    Messages : 57
    Points : 91
    Points
    91
    Par défaut
    Oups, mes excuses, je n'avais pas vu que le premier chiffre était le nombre de chiffres de la ligne; du coup, c'est plus facile, on peut le lire dans la chaîne de caractères, allouer le vecteur et lire le reste de la chaîne (du style:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    READ(dummy(3:len_trim(dummy)),*) stock
    sans analyser la chaîne intermédiaire.

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Juin 2010
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2010
    Messages : 31
    Points : 14
    Points
    14
    Par défaut
    merci les gars.

    c'est vrai que j'avais pensé à ta solution François, mais ne savait comment la mettre en oeuvre.
    je vais testé.

    merci

Discussions similaires

  1. Réponses: 1
    Dernier message: 25/05/2007, 11h55
  2. Réponses: 3
    Dernier message: 12/06/2006, 12h18
  3. [C#] Une variable dans une chaine de caractères...
    Par GlorfindelHebril dans le forum Windows Forms
    Réponses: 9
    Dernier message: 31/03/2005, 15h30
  4. Lire Une Chaine De Caractères
    Par Jonathan_Korvitch dans le forum C
    Réponses: 12
    Dernier message: 07/01/2003, 06h37
  5. Réponses: 2
    Dernier message: 06/12/2002, 08h50

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo