@@ -406,12 +406,16 @@ const _pwf_defaults = Dict("DBAR" => _default_dbar, "DLIN" => _default_dlin, "DC
406
406
407
407
const title_identifier = " TITU"
408
408
const end_section_identifier = " 99999"
409
+ const commented_line_identifier = ' ('
409
410
410
- function _remove_titles_from_file_lines (file_lines:: Vector{String} , section_titles_idx:: Vector{Int64} )
411
- remove_titles_idx = vcat (section_titles_idx, section_titles_idx .+ 1 )
412
- file_lines_without_titles_idx = setdiff (1 : length (file_lines), remove_titles_idx)
413
- file_lines = file_lines[file_lines_without_titles_idx]
414
- return file_lines
411
+ function _is_valid_line (line_number:: Int64 , file_lines:: Vector{String} )
412
+ line = file_lines[line_number]
413
+ if line_number == 1
414
+ return ! isempty (line) && ! startswith (line, commented_line_identifier) && line != title_identifier
415
+ else
416
+ previous_line = file_lines[line_number - 1 ]
417
+ return ! isempty (line) && ! startswith (line, commented_line_identifier) && line != title_identifier && previous_line != title_identifier
418
+ end
415
419
end
416
420
417
421
"""
@@ -422,43 +426,37 @@ element corresponds to a section, divided by the delimiter 99999.
422
426
"""
423
427
function _split_sections (io:: IO )
424
428
file_lines = readlines (io)
425
- filter! (x -> x != " " && x[1 ] != ' (' , file_lines) # Ignore commented and empty lines
426
429
file_lines = replace .(file_lines, repeat ([Char (65533 ) => ' ' ], length (file_lines)))
427
- sections = Vector {String}[]
430
+ sections = Dict {String, Vector{Int64}} ()
428
431
429
432
section_titles_idx = findall (line -> line == title_identifier, file_lines)
430
433
if ! isempty (section_titles_idx)
431
- last_section_title_idx = section_titles_idx[end ]: section_titles_idx[end ] + 1
432
- push! (sections, file_lines[last_section_title_idx])
434
+ sections[title_identifier] = [section_titles_idx[end ] + 1 ]
433
435
end
434
436
435
- file_lines = _remove_titles_from_file_lines (
436
- file_lines, section_titles_idx
437
- )
438
-
439
437
section_delim = vcat (
440
438
0 ,
441
439
findall (x -> x == end_section_identifier, file_lines)
442
440
)
443
441
444
442
num_sections = length (section_delim) - 1
443
+ num_lines = length (file_lines)
445
444
446
445
for i in 1 : num_sections
447
- section_begin_idx = section_delim[i] + 1
446
+ section_name_idx = filter (idx -> _is_valid_line (idx, file_lines), section_delim[i] + 1 : num_lines)[1 ]
447
+ section_name = file_lines[section_name_idx]
448
+
449
+ section_begin_idx = section_name_idx + 1
448
450
section_end_idx = section_delim[i + 1 ] - 1
449
451
450
- # Account for multiple sections in the same pwf
451
- section_i = findall (x -> x[1 ] == file_lines[section_begin_idx], sections)
452
- @assert length (section_i) < 2
453
- if length (section_i) == 0
454
- push! (sections, file_lines[section_begin_idx: section_end_idx])
455
- else
456
- section_i = section_i[1 ]
457
- sections[section_i] = vcat (sections[section_i], file_lines[section_begin_idx + 1 : section_end_idx])
458
- end
452
+ section_range = collect (section_begin_idx: section_end_idx)
453
+ filter! (idx -> _is_valid_line (idx, file_lines), section_range)
454
+
455
+ current = get (sections, section_name, Int64[])
456
+ sections[section_name] = vcat (current, section_range)
459
457
end
460
458
461
- return sections
459
+ return file_lines, sections
462
460
end
463
461
464
462
function _handle_implicit_decimal_point! (
475
473
Internal function. Parses a single line of data elements from a PWF file
476
474
and saves it into `data::Dict`.
477
475
"""
478
- function _parse_line_element! (data:: Dict{String, Any} , line:: String , section:: AbstractString )
479
-
476
+ function _parse_line_element! (data:: Dict{String, Any} , line_number:: Int64 , section:: AbstractString , file_lines:: Vector{String} )
477
+ line = file_lines[line_number]
478
+
480
479
line_length = _pwf_dtypes[section][end ][3 ][end ]
481
480
if length (line) < line_length
482
481
extra_characters_needed = line_length - length (line)
@@ -498,7 +497,8 @@ function _parse_line_element!(data::Dict{String, Any}, line::String, section::Ab
498
497
end
499
498
catch message
500
499
if ! _needs_default (element)
501
- throw (Memento. error (_LOGGER, " Parsing error at section $section : $field should be of type $dtype , received $element " ))
500
+ throw (Memento. error (_LOGGER, " Parsing error in line $line_number at section $section :
501
+ $field should be of type $dtype , received $element " ))
502
502
end
503
503
data[field] = element
504
504
end
@@ -507,11 +507,12 @@ function _parse_line_element!(data::Dict{String, Any}, line::String, section::Ab
507
507
508
508
end
509
509
510
- function _parse_line_element! (data:: Dict{String, Any} , lines :: Vector{String } , section:: AbstractString )
510
+ function _parse_line_element! (data:: Dict{String, Any} , lines_idx :: Vector{Int64 } , section:: AbstractString , file_lines :: Vector{String} )
511
511
512
512
mn_keys, mn_values, mn_type = _mnemonic_pairs[section]
513
513
514
- for line in lines
514
+ for line_number in lines_idx
515
+ line = file_lines[line_number]
515
516
for i in 1 : length (mn_keys)
516
517
k, v = mn_keys[i], mn_values[i]
517
518
if v[end ] <= length (line)
@@ -521,8 +522,9 @@ function _parse_line_element!(data::Dict{String, Any}, lines::Vector{String}, se
521
522
data[line[k]] = parse (mn_type, line[v])
522
523
catch message
523
524
if ! _needs_default (line[v])
524
- throw (Memento. error (_LOGGER, " Parsing error at section $section : $field should be of type $dtype , received $element " ))
525
- end
525
+ throw (Memento. error (_LOGGER, " Parsing error in line $line_number at section $section :
526
+ $field should be of type $dtype , received $element " ))
527
+ end
526
528
! _needs_default (line[k]) ? data[line[k]] = line[v] : nothing
527
529
end
528
530
else
@@ -539,42 +541,43 @@ end
539
541
Internal function. Parses a section containing a system component.
540
542
Returns a Vector of Dict, where each entry corresponds to a single element.
541
543
"""
542
- function _parse_section_element! (data:: Dict{String, Any} , section_lines :: Vector{String } , section:: AbstractString , idx:: Int64 = 1 )
544
+ function _parse_section_element! (data:: Dict{String, Any} , section_lines_idx :: Vector{Int64 } , section:: AbstractString , file_lines :: Vector{String} , idx:: Int64 = 1 )
543
545
544
546
if section == " DBAR"
545
- for line in section_lines[ 2 : end ]
547
+ for line_number in section_lines_idx
546
548
547
549
line_data = Dict {String, Any} ()
548
- _parse_line_element! (line_data, line , section)
550
+ _parse_line_element! (line_data, line_number , section, file_lines )
549
551
550
552
bus_i = line_data[" NUMBER" ]
551
553
data[" $bus_i " ] = line_data
552
554
end
553
555
554
556
else
555
- for line in section_lines[ 2 : end ]
557
+ for line_number in section_lines_idx
556
558
557
559
line_data = Dict {String, Any} ()
558
- _parse_line_element! (line_data, line , section)
560
+ _parse_line_element! (line_data, line_number , section, file_lines )
559
561
560
562
data[" $idx " ] = line_data
561
563
idx += 1
562
564
end
563
565
end
564
566
end
565
567
566
- function _parse_divided_section! (data:: Dict{String, Any} , section_lines:: Vector{String} , section:: String )
568
+ function _parse_divided_section! (data:: Dict{String, Any} , section_lines_idx:: Vector{Int64} , section:: String , file_lines:: Vector{String} )
569
+ section_lines = file_lines[section_lines_idx]
567
570
568
571
separator = _divided_sections[section][" separator" ]
569
- sub_titles_idx = vcat (1 , findall (x -> x == separator, section_lines))
572
+ sub_titles_idx = vcat (0 , findall (x -> x == separator, section_lines))
570
573
for (i, idx) in enumerate (sub_titles_idx)
571
574
572
575
if idx != sub_titles_idx[end ]
573
576
next_idx = sub_titles_idx[i + 1 ]
574
- _parse_section_element! (data, section_lines[ idx: idx + 1 ], _divided_sections[section][" first name" ], i)
577
+ _parse_section_element! (data, [section_lines_idx[ idx + 1 ]] , _divided_sections[section][" first name" ], file_lines , i)
575
578
576
579
rc = Dict {String, Any} ()
577
- _parse_section_element! (rc, section_lines [idx + 1 : next_idx - 1 ], _divided_sections[section][" second name" ], i)
580
+ _parse_section_element! (rc, section_lines_idx [idx + 2 : next_idx - 1 ], _divided_sections[section][" second name" ], file_lines , i)
578
581
579
582
group = _divided_sections[section][" subgroup" ]
580
583
data[" $i " ][group] = rc
@@ -589,21 +592,21 @@ end
589
592
Internal function. Receives an array of lines corresponding to a PWF section,
590
593
transforms it into a Dict and saves it into `data::Dict`.
591
594
"""
592
- function _parse_section! (data:: Dict{String, Any} , section_lines:: Vector{String} )
593
- section = section_lines[1 ]
595
+ function _parse_section! (data:: Dict{String, Any} , section:: String , section_lines_idx:: Vector{Int64} , file_lines:: Vector{String} )
594
596
section_data = Dict {String, Any} ()
595
597
596
598
if section == title_identifier
597
- section_data = section_lines[end ]
599
+ @assert length (section_lines_idx) == 1
600
+ section_data = file_lines[section_lines_idx[1 ]]
598
601
599
602
elseif section in keys (_mnemonic_pairs)
600
- _parse_line_element! (section_data, section_lines[ 2 : end ] , section)
603
+ _parse_line_element! (section_data, section_lines_idx , section, file_lines )
601
604
602
605
elseif section in keys (_pwf_dtypes)
603
- _parse_section_element! (section_data, section_lines , section)
606
+ _parse_section_element! (section_data, section_lines_idx , section, file_lines )
604
607
605
608
elseif section in keys (_divided_sections)
606
- _parse_divided_section! (section_data, section_lines , section)
609
+ _parse_divided_section! (section_data, section_lines_idx , section, file_lines )
607
610
608
611
else
609
612
Memento. warn (_LOGGER, " Currently there is no support for $section parsing" )
@@ -820,11 +823,11 @@ Internal function. Receives a pwf file as an IOStream and parses into a Dict.
820
823
"""
821
824
function _parse_pwf_data (data_io:: IO )
822
825
823
- sections = _split_sections (data_io)
826
+ file_lines, sections = _split_sections (data_io)
824
827
pwf_data = Dict {String, Any} ()
825
828
pwf_data[" name" ] = match (r" ^\< file\s [\/\\ ]*(?:.*[\/\\ ])*(.*)\. pwf\> $" , lowercase (data_io. name)). captures[1 ]
826
- for section in sections
827
- _parse_section! (pwf_data, section)
829
+ for (section_name, section) in sections
830
+ _parse_section! (pwf_data, section_name, section, file_lines )
828
831
end
829
832
_populate_defaults! (pwf_data)
830
833
0 commit comments