module DictionaryClass use, intrinsic :: iso_fortran_env use uuid_module use MathClass use IOClass implicit none type :: Page_ character(:), allocatable :: charvalue ! type_id = 3 character(:), allocatable :: key integer(int32) :: type_id = 0 integer(int32) :: IntValue ! type_id=1 real(real64) :: RealValue ! type_id=2 integer(int32), allocatable :: intlist(:)! type_id/=3, 4 real(real64), allocatable :: realist(:) ! type_id/=4, 5 ! if value is in dicts(:), type_id = -1 end type type :: Dictionary_ character(len=36) :: uuid = "" type(Page_), allocatable :: pages(:) logical :: initialized = .false. integer(int32) :: num_entity = 0 contains procedure :: Init => InitializeDictionary procedure :: Input => InputDictionary procedure :: Get => GetDictionaryValue procedure :: GetPageNum => GetPageNumDictionary procedure :: sizeof => sizeofDictionary procedure :: content => contentofDictionary procedure :: intlist => intlistofDictionary procedure :: intvalue => intvalueofDictionary procedure :: realvalue => realvalueofDictionary procedure :: show => showDictionary procedure :: export => exportDictionary procedure :: destroy => destroyDictionary procedure :: remove => destroyDictionary ! python-like api ! init by dict() procedure, pass :: updateDictionaryInt procedure, pass :: updateDictionaryReal64 procedure, pass :: updateDictionaryChar procedure, pass :: updateDictionaryDictionary generic :: update => updateDictionaryInt, updateDictionaryReal64, & updateDictionaryChar, updateDictionaryDictionary procedure :: find => findDictionary procedure :: findID => findIDDictionary procedure :: to_csv => to_csvDictionary procedure :: to_json => to_jsonDictionary end type type, extends(Page_) :: FileInfo_ character*200 :: Path character*200 :: DirectoryName character*200 :: FileName integer(int32):: FileID end type type :: FileList_ type(FileInfo_), allocatable:: FileList(:) contains procedure :: setFilePath procedure :: setDirectoryName procedure :: setFileName end type interface count module procedure count_char_char end interface count interface split module procedure splitChar_Dict end interface interface from_json module procedure from_JSON_IOClass end interface interface str module procedure str_from_dict, str_from_intvec, str_from_realvec end interface interface operator(>) module procedure findDictionary end interface contains ! ################################################## subroutine updateDictionaryInt(this, Key, intvalue) class(Dictionary_), intent(inout)::this character(*), intent(in) :: key integer(int32), intent(in) :: intvalue integer(int32) :: found_key(2), n type(Dictionary_) :: buf if (this%uuid == "") then this%uuid = generate_uuid(1) end if if (this%num_entity + 1 >= size(this%pages)) then ! copy buf = this ! initialize if (allocated(this%pages)) then deallocate (this%pages) end if allocate (this%pages(buf%num_entity + 1000)) this%pages(1:buf%num_entity) = buf%pages(1:buf%num_entity) end if found_key = this%findID(Key) if (found_key(1) == 0) then this%num_entity = this%num_entity + 1 this%pages(this%num_entity)%key = key this%pages(this%num_entity)%intValue = intValue this%pages(this%num_entity)%type_id = 1 else n = found_key(1) this%pages(n)%key = key this%pages(n)%intValue = intValue this%pages(n)%type_id = 1 end if end subroutine ! ################################################## ! ################################################## subroutine updateDictionaryReal64(this, Key, realValue) class(Dictionary_), intent(inout)::this character(*), intent(in) :: key real(real64), intent(in) :: realValue integer(int32) :: found_key(2), n type(Dictionary_) :: buf if (this%uuid == "") then this%uuid = generate_uuid(1) end if if (this%num_entity + 1 >= size(this%pages)) then ! copy buf = this ! initialize if (allocated(this%pages)) then deallocate (this%pages) end if allocate (this%pages(buf%num_entity + 1000)) this%pages(1:buf%num_entity) = buf%pages(1:buf%num_entity) end if found_key = this%findID(Key) if (found_key(1) == 0) then this%num_entity = this%num_entity + 1 this%pages(this%num_entity)%key = key this%pages(this%num_entity)%realValue = realValue this%pages(this%num_entity)%type_id = 2 else n = found_key(1) this%pages(n)%key = key this%pages(n)%realValue = realValue this%pages(n)%type_id = 2 end if end subroutine ! ################################################## ! ################################################## subroutine updateDictionaryChar(this, Key, charValue) class(Dictionary_), intent(inout)::this character(*), intent(in) :: key character(*), intent(in) :: charValue integer(int32) :: found_key(2), n type(Dictionary_) :: buf if (.not. this%initialized) then call this%init(1) this%num_entity = 1 this%pages(this%num_entity)%key = key this%pages(this%num_entity)%charValue = charValue this%pages(this%num_entity)%type_id = 3 this%initialized = .true. return end if if (this%uuid == "") then this%uuid = generate_uuid(1) end if if (this%num_entity + 1 >= size(this%pages)) then ! copy buf = this ! initialize if (allocated(this%pages)) then deallocate (this%pages) end if allocate (this%pages(buf%num_entity + 1000)) this%pages(1:buf%num_entity) = buf%pages(1:buf%num_entity) end if found_key = this%findID(Key) if (found_key(1) == 0) then this%num_entity = this%num_entity + 1 this%pages(this%num_entity)%key = key this%pages(this%num_entity)%charValue = charValue this%pages(this%num_entity)%type_id = 3 else n = found_key(1) this%pages(n)%key = key this%pages(n)%charValue = charValue this%pages(n)%type_id = 3 end if end subroutine ! ################################################## !! ################################################## !subroutine updateDictionaryDictionary(this,Key, dictValue) ! class(Dictionary_),intent(inout)::this ! character(*),intent(in) :: key ! type(Dictionary_),intent(in) :: dictValue ! integer(int32) :: found_key(2),n ! type(Dictionary_) :: buf ! ! ! if(this%uuid=="")then ! this%uuid = generate_uuid(1) ! endif ! ! if(this%num_entity+1 >= size(this%pages) )then ! ! copy ! buf = this ! ! initialize ! if(allocated(this%pages) )then ! deallocate(this%pages) ! endif ! allocate(this%pages(buf%num_entity + 1000) ) ! this%pages(1:buf%num_entity) = buf%pages(1:buf%num_entity) ! ! ! !if(allocated(this%dicts)) then ! ! deallocate(this%dicts) ! !endif ! !allocate(this%dicts(buf%num_entity + 1000) ) ! !this%dicts(1:buf%num_entity) = buf%dicts(1:buf%num_entity) ! ! endif ! ! found_key=this%findID(Key) ! ! if(found_key(1)==0 )then ! ! new ! this%num_entity = this%num_entity + 1 ! this%pages(this%num_entity)%key = key ! this%dicts(this%num_entity) = dictValue ! this%pages(this%num_entity)%type_id = -1 ! else ! ! not loaded ! n = found_key(1) ! this%pages(n)%key = key ! this%dicts(n) = dictValue ! this%pages(n)%type_id = -1 ! endif ! ! !end subroutine !! ################################################## ! ################################################## subroutine updateDictionaryDictionary(this, Key, dictValue) class(Dictionary_), intent(inout)::this character(*), intent(in) :: key character(:), allocatable :: charValue type(Dictionary_), intent(in) :: dictValue integer(int32) :: found_key(2), n type(Dictionary_) :: buf charValue = str(dictValue) if (.not. this%initialized) then call this%init(1) this%num_entity = 1 this%pages(this%num_entity)%key = key this%pages(this%num_entity)%charValue = charValue this%pages(this%num_entity)%type_id = -1 this%initialized = .true. return end if if (this%uuid == "") then this%uuid = generate_uuid(1) end if if (this%num_entity + 1 >= size(this%pages)) then ! copy buf = this ! initialize if (allocated(this%pages)) then deallocate (this%pages) end if allocate (this%pages(buf%num_entity + 1000)) this%pages(1:buf%num_entity) = buf%pages(1:buf%num_entity) end if found_key = this%findID(Key) if (found_key(1) == 0) then this%num_entity = this%num_entity + 1 this%pages(this%num_entity)%key = key this%pages(this%num_entity)%charValue = charValue this%pages(this%num_entity)%type_id = -1 else n = found_key(1) this%pages(n)%key = key this%pages(n)%charValue = charValue this%pages(n)%type_id = -1 end if end subroutine ! ################################################## ! ################################################## function to_dict(name) result(ret_dict) type(Dictionary_) :: ret_dict character(*), intent(in) :: name type(IO_) :: f integer(int32) :: i, num_col, id_from, id_to character(:), allocatable :: line, value_, key_ if ("{".in.name) then if (.not. (".json".in.name)) then ! parse name as json ret_dict = parse_json_as_dict(name) return end if end if ret_dict = dict() call f%open(name) do if (f%EOF) exit line = f%readline() num_col = count(line, ",") id_to = 1 id_from = 1 if (num_col < 2) cycle key_ = "" value_ = "" do i = 1, 2 id_to = index(line(id_from:), ",") if (id_from + id_to - 1 > len(line)) exit if (i == 1) then key_ = line(id_from:id_to - 1) else value_ = line(id_from:id_from + id_to - 2) end if id_from = id_to + 1 end do key_ = key_(2:) key_ = key_(:len(key_) - 1) if (index(value_, ".") /= 0) then call ret_dict%update(key_, freal(value_)) else call ret_dict%update(key_, fint(value_)) end if end do call f%close() end function ! ############################################## ! ################################################## function dict(max_num_entity) result(ret_dict) type(Dictionary_) :: ret_dict integer(int32), optional, intent(in) :: max_num_entity integer(int32) :: max_entity max_entity = 1000 if (present(max_num_entity)) then max_entity = max_num_entity end if ret_dict%initialized = .true. allocate (ret_dict%pages(max_entity)) end function ! ############################################## subroutine InitializeDictionary(obj, NumOfPage) class(Dictionary_), intent(inout)::obj integer(int32), intent(in) :: NumOfPage if (allocated(obj%pages)) then deallocate (obj%pages) end if allocate (obj%pages(NumOfPage)) obj%initialized = .true. obj%uuid = generate_uuid(1) end subroutine ! ############################################## ! ############################################## subroutine InputDictionary(obj, page, content, RealValue, IntValue, Realist, Intlist, DictValue) class(Dictionary_), intent(inout)::obj integer(int32), intent(in) :: page character(*), optional, intent(in) :: Content integer(int32), optional, intent(in) :: IntValue, Intlist(:) real(real64), optional, intent(in) :: RealValue, Realist(:) type(Dictionary_), optional, intent(in) :: DictValue if (page > size(obj%pages)) then print *, "Error :: InputDictionary >> Num of Page is overflowed" stop end if if (present(RealValue)) then obj%pages(page)%RealValue = RealValue return end if if (present(Realist)) then if (allocated(obj%pages(page)%Realist)) then deallocate (obj%pages(page)%Realist) end if allocate (obj%pages(page)%Realist(size(Realist, 1))) obj%pages(page)%Realist(:) = Realist(:) return end if if (present(IntValue)) then obj%pages(page)%intValue = intValue return end if if (present(intlist)) then if (allocated(obj%pages(page)%intlist)) then deallocate (obj%pages(page)%intlist) end if allocate (obj%pages(page)%intlist(size(intlist, 1))) obj%pages(page)%intlist(:) = intlist(:) return end if if (present(content)) then obj%pages(page)%charValue = content end if end subroutine ! ############################################## ! ############################################## function intlistofDictionary(obj, page, ind) result(n) class(Dictionary_), intent(in) :: obj integer(int32), intent(in) :: page, ind integer(int32) :: n n = obj%pages(page)%intlist(ind) end function ! ############################################## ! ############################################## function intvalueofDictionary(obj, page) result(n) class(Dictionary_), intent(in) :: obj integer(int32), intent(in) :: page integer(int32) :: n n = obj%pages(page)%intvalue end function ! ############################################## ! ############################################## function realvalueofDictionary(obj, page) result(n) class(Dictionary_), intent(in) :: obj integer(int32), intent(in) :: page real(real64) :: n n = obj%pages(page)%realvalue end function ! ############################################## ! ############################################## function GetDictionaryValue(obj, page) result(content) class(Dictionary_), intent(in)::obj integer(int32), intent(in) :: page character(:), allocatable :: content if (page > size(obj%pages)) then content = "" return end if content = obj%pages(page)%charValue end function ! ############################################## ! ############################################## subroutine setFilePath(obj, FilePath, FileID) class(FileList_), intent(inout)::obj integer(int32), intent(in) :: FileID character*200, intent(in) :: FilePath obj%FileList(FileID)%Path = FilePath end subroutine ! ############################################## ! ############################################## subroutine setDirectoryName(obj, DirectoryName, FileID) class(FileList_), intent(inout)::obj integer(int32), intent(in) :: FileID character*200, intent(in) :: DirectoryName obj%FileList(FileID)%DirectoryName = DirectoryName end subroutine ! ############################################## ! ############################################## subroutine setFileName(obj, FileName, FileID) class(FileList_), intent(inout)::obj integer(int32), intent(in) :: FileID character*200, intent(in) :: FileName obj%FileList(FileID)%FileName = FileName end subroutine ! ############################################## ! ############################################## subroutine showDictionary(obj, From, to, Name) class(Dictionary_)::obj integer(int32), optional, intent(in)::From, to character(*), optional, intent(in) :: Name integer(int32) :: i, n, startp, endp, rl, il n = obj%num_entity startp = input(default=1, option=From) endp = input(default=n, option=to) do i = startp, endp rl = 0 il = 0 if (.not. allocated(obj%pages(i)%Intlist)) then allocate (obj%pages(i)%Intlist(0)) il = 1 end if if (.not. allocated(obj%pages(i)%Realist)) then allocate (obj%pages(i)%Realist(0)) rl = 1 end if if (obj%pages(i)%type_id == 1) then print *, '{"'+obj%pages(i)%Key + '":', & str(obj%pages(i)%IntValue) + "}" elseif (obj%pages(i)%type_id == 2) then print *, '{"'+obj%pages(i)%Key + '":', & str(obj%pages(i)%realValue) + "}" elseif (obj%pages(i)%type_id == 3) then print *, '{"'+obj%pages(i)%Key + '":', & obj%pages(i)%charValue + "}" else ! do nothing end if if (il == 1) then deallocate (obj%pages(i)%Intlist) end if if (rl == 1) then deallocate (obj%pages(i)%Realist) end if end do if (present(Name)) then open (1023, file=Name) do i = startp, endp rl = 0 il = 0 if (.not. allocated(obj%pages(i)%Intlist)) then allocate (obj%pages(i)%Intlist(0)) il = 1 end if if (.not. allocated(obj%pages(i)%Realist)) then allocate (obj%pages(i)%Realist(0)) rl = 1 end if write (1023, *) "Page : ", i, "Content : ", obj%pages(i)%charValue, & "IntValue : ", obj%pages(i)%IntValue, & "RealValue : ", obj%pages(i)%RealValue, & "Intlist(:) : ", obj%pages(i)%Intlist(:), & "Realist(:) : ", obj%pages(i)%Realist(:) if (il == 1) then deallocate (obj%pages(i)%Intlist) end if if (rl == 1) then deallocate (obj%pages(i)%Realist) end if end do close (1023) end if end subroutine ! ############################################## ! ############################################## subroutine exportDictionary(obj, FileName, fh, from, to) class(Dictionary_)::obj integer(int32), optional, intent(in)::From, to, fh character(*), intent(in) :: FileName integer(int32) :: i, n, startp, endp, rl, il, nnn n = size(obj%pages, 1) startp = input(default=1, option=From) endp = input(default=n, option=to) nnn = input(default=1000, option=fh) open (nnn, file=FileName) do i = startp, endp rl = 0 il = 0 if (.not. allocated(obj%pages(i)%Intlist)) then allocate (obj%pages(i)%Intlist(0)) il = 1 end if if (.not. allocated(obj%pages(i)%Realist)) then allocate (obj%pages(i)%Realist(0)) rl = 1 end if write (nnn, *) "Page : ", i, "Content : ", obj%pages(i)%charValue, & "IntValue : ", obj%pages(i)%IntValue, & "RealValue : ", obj%pages(i)%RealValue, & "Intlist(:) : ", obj%pages(i)%Intlist(:), & "Realist(:) : ", obj%pages(i)%Realist(:) if (il == 1) then deallocate (obj%pages(i)%Intlist) end if if (rl == 1) then deallocate (obj%pages(i)%Realist) end if end do close (nnn) end subroutine ! ############################################## ! ############################################## function sizeofDictionary(obj) result(n) class(Dictionary_), intent(in) :: obj integer(int32) :: n n = size(obj%pages) end function ! ############################################## ! ############################################## function contentofDictionary(obj, id) result(content) class(Dictionary_), intent(in) :: obj integer(int32), intent(in) :: id character*200 :: content content = obj%pages(id)%charvalue end function ! ############################################## ! ############################################## function GetPageNumDictionary(obj, Content) result(page) class(Dictionary_), intent(in)::obj character(*), intent(in)::Content integer(int32) :: page integer(int32) :: i, n n = size(obj%pages, 1) page = -1 do i = 1, n if (Content == obj%pages(i)%charvalue) then page = i return end if end do if (page == -1) then print *, "ERROR ::", Content, " is a word to be found only in the dictionary of fools." end if end function ! ############################################## ! ############################################## subroutine destroyDictionary(obj) class(Dictionary_), intent(inout) :: obj if (allocated(obj%pages)) then deallocate (obj%pages) end if obj%initialized = .false. end subroutine ! ############################################## ! ############################################## recursive function findDictionary(this, key) result(val) class(Dictionary_), intent(in) :: this character(*), intent(in) :: key character(:), allocatable :: val integer(int32) :: i do i = 1, this%num_entity if (this%pages(i)%key == Key) then ! Found! select case (this%pages(i)%type_id) case (-1) val = this%pages(i)%charValue return case (1) val = str(this%pages(i)%intValue) return case (2) val = str(this%pages(i)%realValue) return case (3) val = this%pages(i)%charValue return end select end if end do val = "__None__" end function ! ############################################## ! ############################################## recursive function findIDDictionary(this, key) result(val) class(Dictionary_), intent(in) :: this character(*), intent(in) :: key integer(int32) :: val(2) integer(int32) :: i do i = 1, this%num_entity if (this%pages(i)%key == Key) then ! Found! val(1) = i val(2) = this%pages(i)%type_id return end if end do val = 0 end function subroutine to_csvDictionary(obj, Name, from, to) class(Dictionary_)::obj integer(int32), optional, intent(in)::From, to character(*), intent(in) :: Name type(IO_) :: f integer(int32) :: i, n, startp, endp, rl, il n = obj%num_entity startp = input(default=1, option=From) endp = input(default=n, option=to) call f%open(Name + ".csv") do i = startp, endp rl = 0 il = 0 if (.not. allocated(obj%pages(i)%Intlist)) then allocate (obj%pages(i)%Intlist(0)) il = 1 end if if (.not. allocated(obj%pages(i)%Realist)) then allocate (obj%pages(i)%Realist(0)) rl = 1 end if if (obj%pages(i)%type_id == 1) then write (f%fh, *) '"'+obj%pages(i)%Key + '",', & str(obj%pages(i)%IntValue) + "," elseif (obj%pages(i)%type_id == 2) then write (f%fh, *) '"'+obj%pages(i)%Key + '",', & str(obj%pages(i)%realValue) + "," elseif (obj%pages(i)%type_id == 3) then write (f%fh, *) '"'+obj%pages(i)%Key + '",', & obj%pages(i)%charvalue + "," else ! do nothing end if if (il == 1) then deallocate (obj%pages(i)%Intlist) end if if (rl == 1) then deallocate (obj%pages(i)%Realist) end if end do call f%close() end subroutine subroutine to_jsonDictionary(obj, Name, from, to) class(Dictionary_)::obj integer(int32), optional, intent(in)::From, to character(*), intent(in) :: Name type(IO_) :: f integer(int32) :: i, n, startp, endp, rl, il n = obj%num_entity startp = input(default=1, option=From) endp = input(default=n, option=to) call f%open(Name + ".json") call f%write("{") do i = startp, endp - 1 rl = 0 il = 0 if (.not. allocated(obj%pages(i)%Intlist)) then allocate (obj%pages(i)%Intlist(0)) il = 1 end if if (.not. allocated(obj%pages(i)%Realist)) then allocate (obj%pages(i)%Realist(0)) rl = 1 end if if (obj%pages(i)%type_id == 1) then write (f%fh, *) '"'+obj%pages(i)%Key + '": ', & str(obj%pages(i)%IntValue) + "," elseif (obj%pages(i)%type_id == 2) then write (f%fh, *) '"'+obj%pages(i)%Key + '": ', & str(obj%pages(i)%realValue) + "," elseif (obj%pages(i)%type_id == 3) then write (f%fh, *) '"'+obj%pages(i)%Key + '": ', & obj%pages(i)%charValue + "," else ! do nothing end if if (il == 1) then deallocate (obj%pages(i)%Intlist) end if if (rl == 1) then deallocate (obj%pages(i)%Realist) end if end do i = endp if (obj%pages(i)%type_id == 1) then write (f%fh, *) '"'+obj%pages(i)%Key + '": ', & str(obj%pages(i)%IntValue) elseif (obj%pages(i)%type_id == 2) then write (f%fh, *) '"'+obj%pages(i)%Key + '": ', & str(obj%pages(i)%realValue) elseif (obj%pages(i)%type_id == 3) then write (f%fh, *) '"'+obj%pages(i)%Key + '": ', & obj%pages(i)%charValue else ! do nothing end if call f%write("}") call f%close() end subroutine ! ########################################################### ! ########################################################### recursive function count_char_char(sentence, key, initialized) result(ret) character(*), intent(in) :: sentence character(*), intent(in) :: key character(:), allocatable :: small_sentence logical, optional, intent(in) :: initialized integer(int32) :: n_len, k integer(int32) :: ret n_len = len(sentence) if (present(initialized)) then if (initialized) then ! nothing to do else ret = 0.0d0 end if else ret = 0.0d0 end if if (index(sentence, key) == 0) then return else ret = ret + 1 if (index(sentence, key) + 1 > n_len) return small_sentence = sentence(index(sentence, key) + 1:) ret = ret + & count_char_char(sentence=small_sentence, key=key, initialized=.true.) end if end function ! ########################################################### ! ########################################################### function splitChar_Dict(line, splitter) result(ret_dict) character(*), intent(in) :: line, splitter integer(int32) :: i, n, from type(Dictionary_) :: ret_dict n = count(line, splitter) call ret_dict%init(n + 1) from = 1 ret_dict%pages(1)%charvalue = line(:index(line, splitter) - 1) from = from + len(ret_dict%pages(1)%charvalue) + len(splitter) do i = 2, n ret_dict%pages(i)%charvalue = line(:index(line(from:), splitter) - 1) from = from + len(ret_dict%pages(1)%charvalue) + len(splitter) end do ret_dict%pages(n + 1)%charvalue = line(from:) end function ! ########################################################### ! ##################################################################### recursive function from_JSON_IOClass(filename, from_line_idx, only_num_bracket) result(ret) character(*), intent(in) :: filename integer(int32), optional, intent(in) :: from_line_idx, only_num_bracket type(IO_) :: f, debug type(Dictionary_) :: ret, mini_dict type(List_) :: key_and_value character(:), allocatable :: line integer(int32) :: num_bracket, line_idx call ret%init(NumOfPage=get_num_entity_json(filename)) call debug%open("debug.txt", "w") call f%open(filename, "r") num_bracket = 0 line_idx = 0 do line_idx = line_idx + 1 if (f%EOF) exit if (present(only_num_bracket)) then if (num_bracket /= only_num_bracket) exit end if if (present(from_line_idx)) then if (from_line_idx > line_idx) then cycle end if end if line = f%readline() if (num_bracket == 1 .and. (":".in.line)) then ! primary layer call replace(line, "'", "") call replace(line, '"', "") !call replace(line," ","") call replace(line, ",", "") call key_and_value%split(line, delimiter=":") call debug%write(line) call ret%update(key_and_value%get(1), key_and_value%get(2)) elseif (num_bracket >= 2) then ! nested mini_dict = from_JSON_IOClass(filename, from_line_idx=line_idx, only_num_bracket=num_bracket) !key_and_value%content(2)%char = key_and_value%get(2) + line call ret%update(key_and_value%get(1), mini_dict) end if if ("{".in.line) then num_bracket = num_bracket + 1 ! end if if ("}".in.line) then num_bracket = num_bracket - 1 end if if (len(trim(line)) == 0) then call debug%write("[space]") cycle else call debug%write(str(line_idx) + " "+str(num_bracket)) end if end do call debug%close() call f%close() end function ! ##################################################################### function get_num_entity_json(filename) result(ret) type(IO_) :: f, debug character(*), intent(in) :: filename integer(int32) :: ret character(:), allocatable :: line integer(int32) :: num_bracket, line_idx ret = 0 call f%open(filename, "r") num_bracket = 0 line_idx = 0 do line_idx = line_idx + 1 if (f%EOF) exit line = f%readline() if (num_bracket == 1) then ! primary layer ret = ret + 1 end if if ("{".in.line) then num_bracket = num_bracket + 1 ! end if if ("}".in.line) then num_bracket = num_bracket - 1 end if if (len(trim(line)) == 0) then cycle end if end do call f%close() end function ! ##################################################################### ! ##################################################################### recursive function str_from_dict(dict) result(ret) type(Dictionary_), intent(in) :: dict character(:), allocatable :: ret integer(int32) :: i ret = "" if (.not. allocated(dict%pages)) then return end if if (size(dict%pages) == 0) then return end if ret = ret + '{'+new_line("A") do i = 1, dict%num_entity ret = ret + '"'+dict%pages(i)%key ret = ret + '":' if (dict%pages(i)%type_id == -1) then ! Dictionary型 ret = ret + dict%pages(i)%charValue elseif (dict%pages(i)%type_id == 3) then ! 文字列 ret = ret + '"'+dict%pages(i)%charValue + '"' elseif (dict%pages(i)%type_id == 1) then ret = ret + str(dict%pages(i)%intValue) elseif (dict%pages(i)%type_id == 2) then ret = ret + str(dict%pages(i)%RealValue) elseif (dict%pages(i)%type_id == 4) then ret = ret + str(dict%pages(i)%intlist) elseif (dict%pages(i)%type_id == 5) then ret = ret + str(dict%pages(i)%Realist) end if if (i <= dict%num_entity - 1) then ret = ret + "," end if ret = ret + new_line("A") end do ret = ret + '}' end function ! ##################################################################### ! ##################################################################### function str_from_intvec(intvec) result(ret) integer(int32), intent(in) :: intvec(:) character(:), allocatable :: ret integer(int32) :: i ret = "[" do i = 1, size(intvec) ret = ret + str(intvec(i)) + "," end do ret = ret + "]" end function ! ##################################################################### ! ##################################################################### function str_from_realvec(realvec) result(ret) real(real64), intent(in) :: realvec(:) character(:), allocatable :: ret integer(int32) :: i ret = "[" do i = 1, size(realvec) ret = ret + str(realvec(i)) + "," end do ret = ret + "]" end function ! ##################################################################### ! ##################################################################### ! json文字列をlistにして返す. !----------------------------- recursive function parse_json_as_dict(content, from_line_idx, only_num_bracket) result(ret) character(*), intent(in) :: content integer(int32), optional, intent(in) :: from_line_idx, only_num_bracket type(IO_) :: debug type(Dictionary_) :: ret, mini_dict type(List_) :: key_and_value character(:), allocatable :: line, content_val integer(int32) :: num_bracket, line_idx, num_bracket_L1 ! pre-processing if (.not. (new_line("A") .in.content)) then content_val = content call replace(content_val, "{", "{"+new_line("A")) call replace(content_val, "}", new_line("A") + "}") ret = parse_json_as_dict(content_val, from_line_idx, only_num_bracket) return end if call ret%init(NumOfPage=get_num_entity_json_str(content)) !!! call debug%open("debug.txt", "w") !call f%open(filename,"r") num_bracket = 0 line_idx = 0 do line_idx = line_idx + 1 if (is_EOL(content, line_idx)) exit !!! if (present(from_line_idx)) then if (from_line_idx > line_idx) then cycle end if end if if (present(only_num_bracket)) then if (num_bracket < only_num_bracket) exit end if line = readline(content, line_idx) !!! if (num_bracket == 1 .and. (":".in.line)) then if (("{".in.line) .and. index(line, "{") > index(line, ":")) then ! primary layer call replace(line, "'", "") call replace(line, '"', "") call replace(line, ",", "") call key_and_value%split(line, delimiter=":") num_bracket_L1 = 1 do if (num_bracket_L1 == 0) exit line_idx = line_idx + 1 line = readline(content, line_idx) key_and_value%fcontent(2)%char = key_and_value%fcontent(2)%char + new_line("A") & + line if ("{".in.line) then num_bracket_L1 = num_bracket_L1 + 1 ! end if if ("}".in.line) then num_bracket_L1 = num_bracket_L1 - 1 end if end do call debug%write("debug L1 >> "+str(to_dict(key_and_value%get(2)))) !call debug%write("end mini_dict #1>> "+str(mini_dict)) !key_and_value%content(2)%char = key_and_value%get(2) + line !call ret%update(key_and_value%get(1),key_and_value%get(2)) call ret%update(key_and_value%get(1), to_dict(key_and_value%get(2))) !call debug%write("debug >> "+key_and_value%get(1)+", "+key_and_value%get(2)) !call ret%update(key_and_value%get(1),key_and_value%get(2)) call debug%write("debug Num_line L1 >> "+str(line_idx)) cycle else ! primary layer call replace(line, "'", "") call replace(line, '"', "") call replace(line, ",", "") call key_and_value%split(line, delimiter=":") call debug%write("debug L0 >> "+key_and_value%get(1) + ", "+key_and_value%get(2)) call ret%update(key_and_value%get(1), key_and_value%get(2)) end if elseif (num_bracket >= 2) then ! nested call debug%write("mini_dict >> "+str(mini_dict)) mini_dict = parse_json_as_dict(content, from_line_idx=line_idx, & only_num_bracket=num_bracket) call debug%write("end mini_dict >> "+str(mini_dict)) !key_and_value%content(2)%char = key_and_value%get(2) + line call ret%update(key_and_value%get(1), mini_dict) end if if ("{".in.line) then num_bracket = num_bracket + 1 ! end if if ("}".in.line) then num_bracket = num_bracket - 1 end if if (len(trim(line)) == 0) then call debug%write("[space]") cycle else call debug%write(str(line_idx) + " "+str(num_bracket)) end if end do call debug%close() end function ! ##################################################################### ! ##################################################################### function get_num_entity_json_str(content) result(ret) character(*), intent(in) :: content ! contentにentityが何個あるかを数え上げる. ! contentは改行を含む.(filename) result(ret) type(IO_) :: f, debug integer(int32) :: ret character(:), allocatable :: line integer(int32) :: num_bracket, line_idx ret = 0 !call f%open(filename,"r") num_bracket = 0 line_idx = 0 do line_idx = line_idx + 1 if (is_EOL(content, line_idx)) exit line = readline(content, line_idx) if (num_bracket == 1) then ! primary layer ret = ret + 1 end if if ("{".in.line) then num_bracket = num_bracket + 1 ! end if if ("}".in.line) then num_bracket = num_bracket - 1 if (num_bracket == 0) then ret = ret - 1 end if end if if (len(trim(line)) == 0) then cycle end if end do !call f%close() end function ! ##################################################################### ! ##################################################################### function is_EOL(content, line_idx) result(ret) character(*), intent(in) :: content integer(int32), intent(in) :: line_idx type(List_) :: list_buf logical :: ret call list_buf%split(content, new_line("A")) ! End Of Linesかどうか調べる. if (line_idx <= list_buf%size()) then ret = .false. else ret = .true. end if end function ! ##################################################################### ! ##################################################################### function readline(content, line_idx) result(ret) character(*), intent(in) :: content integer(int32), intent(in) :: line_idx character(:), allocatable :: ret type(List_) :: list ! 特定行を読む. if (is_EOL(content, line_idx)) then ret = "" else call list%split(content, new_line("A")) ret = list%get(line_idx) end if end function ! ##################################################################### end module