11import datetime
2- import re
32from typing import Collection , List , Tuple
43
54import numpy as np
65import pandas as pd
76
87from wfdb .io import _signal
98from wfdb .io import util
10-
9+ from wfdb . io . header import HeaderSyntaxError , rx_record , rx_segment , rx_signal
1110
1211"""
1312Notes
3231 so that the user doesn't need to. But when reading, it should
3332 be clear that the fields are missing.
3433
35- If all of the fields were filled out in a WFDB header file, they would appear
36- in this order with these seperators:
37-
38- RECORD_NAME/NUM_SEG NUM_SIG SAMP_FREQ/COUNT_FREQ(BASE_COUNT_VAL) SAMPS_PER_SIG BASE_TIME BASE_DATE
39- FILE_NAME FORMATxSAMP_PER_FRAME:SKEW+BYTE_OFFSET ADC_GAIN(BASELINE)/UNITS ADC_RES ADC_ZERO CHECKSUM BLOCK_SIZE DESCRIPTION
40-
4134"""
4235int_types = (int , np .int64 , np .int32 , np .int16 , np .int8 )
4336float_types = (float , np .float64 , np .float32 ) + int_types
135128# Specifications of all WFDB header fields, except for comments
136129FIELD_SPECS = pd .concat ((RECORD_SPECS , SIGNAL_SPECS , SEGMENT_SPECS ))
137130
138- # Regexp objects for reading headers
139- # Record line
140- _rx_record = re .compile (
141- r"""
142- [ \t]* (?P<record_name>[-\w]+)
143- /?(?P<n_seg>\d*)
144- [ \t]+ (?P<n_sig>\d+)
145- [ \t]* (?P<fs>\d*\.?\d*)
146- /*(?P<counter_freq>-?\d*\.?\d*)
147- \(?(?P<base_counter>-?\d*\.?\d*)\)?
148- [ \t]* (?P<sig_len>\d*)
149- [ \t]* (?P<base_time>\d{,2}:?\d{,2}:?\d{,2}\.?\d{,6})
150- [ \t]* (?P<base_date>\d{,2}/?\d{,2}/?\d{,4})
151- """ ,
152- re .VERBOSE ,
153- )
154-
155- # Signal line
156- _rx_signal = re .compile (
157- r"""
158- [ \t]* (?P<file_name>~?[-\w]*\.?[\w]*)
159- [ \t]+ (?P<fmt>\d+)
160- x?(?P<samps_per_frame>\d*)
161- :?(?P<skew>\d*)
162- \+?(?P<byte_offset>\d*)
163- [ \t]* (?P<adc_gain>-?\d*\.?\d*e?[\+-]?\d*)
164- \(?(?P<baseline>-?\d*)\)?
165- /?(?P<units>[\w\^\-\?%\/]*)
166- [ \t]* (?P<adc_res>\d*)
167- [ \t]* (?P<adc_zero>-?\d*)
168- [ \t]* (?P<init_value>-?\d*)
169- [ \t]* (?P<checksum>-?\d*)
170- [ \t]* (?P<block_size>\d*)
171- [ \t]* (?P<sig_name>[\S]?[^\t\n\r\f\v]*)
172- """ ,
173- re .VERBOSE ,
174- )
175-
176- # Segment line
177- _rx_segment = re .compile (
178- r"""
179- [ \t]* (?P<seg_name>[-\w]*~?)
180- [ \t]+ (?P<seg_len>\d+)
181- """ ,
182- re .VERBOSE ,
183- )
184-
185131
186132class BaseHeaderMixin (object ):
187133 """
@@ -1013,37 +959,6 @@ def wfdb_strptime(time_string: str) -> datetime.time:
1013959 return datetime .datetime .strptime (time_string , time_fmt ).time ()
1014960
1015961
1016- def parse_header_content (
1017- header_content : str ,
1018- ) -> Tuple [List [str ], List [str ]]:
1019- """
1020- Parse the text of a header file.
1021-
1022- Parameters
1023- ----------
1024- header_content: str
1025- The string content of the full header file
1026-
1027- Returns
1028- -------
1029- header_lines : List[str]
1030- A list of all the non-comment lines
1031- comment_lines : List[str]
1032- A list of all the comment lines
1033- """
1034- header_lines , comment_lines = [], []
1035- for line in header_content .splitlines ():
1036- line = line .strip ()
1037- # Comment line
1038- if line .startswith ("#" ):
1039- comment_lines .append (line )
1040- # Non-empty non-comment line = header line.
1041- elif line :
1042- header_lines .append (line )
1043-
1044- return header_lines , comment_lines
1045-
1046-
1047962def _parse_record_line (record_line : str ) -> dict :
1048963 """
1049964 Extract fields from a record line string into a dictionary.
@@ -1063,7 +978,7 @@ def _parse_record_line(record_line: str) -> dict:
1063978 record_fields = {}
1064979
1065980 # Read string fields from record line
1066- match = _rx_record .match (record_line )
981+ match = rx_record .match (record_line )
1067982 if match is None :
1068983 raise HeaderSyntaxError ("invalid syntax in record line" )
1069984 (
@@ -1139,7 +1054,7 @@ def _parse_signal_lines(signal_lines):
11391054
11401055 # Read string fields from signal line
11411056 for ch in range (n_sig ):
1142- match = _rx_signal .match (signal_lines [ch ])
1057+ match = rx_signal .match (signal_lines [ch ])
11431058 if match is None :
11441059 raise HeaderSyntaxError ("invalid syntax in signal line" )
11451060 (
@@ -1213,7 +1128,7 @@ def _read_segment_lines(segment_lines):
12131128
12141129 # Read string fields from signal line
12151130 for i in range (len (segment_lines )):
1216- match = _rx_segment .match (segment_lines [i ])
1131+ match = rx_segment .match (segment_lines [i ])
12171132 if match is None :
12181133 raise HeaderSyntaxError ("invalid syntax in segment line" )
12191134 (
@@ -1226,7 +1141,3 @@ def _read_segment_lines(segment_lines):
12261141 segment_fields ["seg_len" ][i ] = int (segment_fields ["seg_len" ][i ])
12271142
12281143 return segment_fields
1229-
1230-
1231- class HeaderSyntaxError (ValueError ):
1232- """Invalid syntax found in a WFDB header file."""
0 commit comments