"""Basic functions for searching for keywords in an ascii control file such as a nexus deck.
Ascii file must already have been opened for reading before calling any of these functions.
"""
# Nexus is a registered trademark of the Halliburton Company
import logging
log = logging.getLogger(__name__)
[docs]def substring(shorter, longer):
"""Returns True if the first argument is a substring of the second."""
try:
longer.index(shorter)
return True
except Exception:
return False
[docs]def end_of_file(ascii_file):
"""Returns True if the end of the file has been reached."""
file_pos = ascii_file.tell()
line = ascii_file.readline()
if len(line) == 0:
return True # end of file
ascii_file.seek(file_pos)
return False
[docs]def find_keyword(ascii_file, keyword, max_lines = None):
"""Looks for line starting with given keyword; file pointer is left at start of that line."""
start_pos = ascii_file.tell()
while True:
if max_lines is not None:
if max_lines <= 0:
ascii_file.seek(start_pos)
return False
max_lines -= 1
file_pos = ascii_file.tell()
line = ascii_file.readline()
if len(line) == 0:
ascii_file.seek(start_pos)
return False # end of file
words = line.split()
if len(words) > 0 and words[0].upper() == keyword.upper():
ascii_file.seek(file_pos)
return True
[docs]def find_keyword_without_passing(ascii_file, keyword, no_pass_keyword):
"""Looks for line starting with keyword, but without passing line starting with no_pass_keyword."""
while True:
file_pos = ascii_file.tell()
line = ascii_file.readline()
if len(line) == 0:
return False # end of file
words = line.split()
if len(words) > 0:
if words[0].upper() == keyword.upper():
ascii_file.seek(file_pos)
return True
if words[0].upper() == no_pass_keyword.upper():
ascii_file.seek(file_pos)
return False
[docs]def find_keyword_with_copy(ascii_file_in, keyword, ascii_file_out):
"""Looks for line starting with given keyword, copying lines in the meantime."""
while True:
file_pos = ascii_file_in.tell()
line = ascii_file_in.readline()
if len(line) == 0:
return False # end of file
words = line.split()
if len(words) > 0 and words[0].upper() == keyword.upper():
ascii_file_in.seek(file_pos)
return True
else:
ascii_file_out.write(line)
[docs]def find_keyword_pair(ascii_file, primary_keyword, secondary_keyword):
"""Looks for line starting with a given pair of keywords."""
while True:
if not find_keyword(ascii_file, primary_keyword):
return False
file_pos = ascii_file.tell()
line = ascii_file.readline()
if len(line) == 0:
return False # end of file
words = line.split()
if len(words) >= 2 and words[1].upper() == secondary_keyword.upper():
ascii_file.seek(file_pos)
return True
[docs]def find_number(ascii_file):
"""Looks for line starting with any number."""
while True:
file_pos = ascii_file.tell()
line = ascii_file.readline()
if len(line) == 0:
return False # end of file
words = line.split()
if len(words) > 0:
try:
float(words[0])
except Exception: # todo: should only catch a particular exception (type conversion)
continue
else:
ascii_file.seek(file_pos)
return True
[docs]def specific_keyword_next(ascii_file, keyword, skip_blank_lines = True, comment_char = '!'):
"""Returns True if next token in file is the specified keyword."""
file_pos = ascii_file.tell() # will restore file pos to original, which may be before blank lines
while True:
if (skip_blank_lines):
file_pos = ascii_file.tell() # will advance file pos to next non-blank line
line = ascii_file.readline()
if len(line) == 0: # end of file
ascii_file.seek(file_pos)
return False
words = line.split()
if len(words) == 0 or words[0][0] == comment_char:
continue # blank line or comment
ascii_file.seek(file_pos) # restore file position whether or not keyword match
if words[0].upper() == keyword.upper():
return True
return False
[docs]def number_next(ascii_file, skip_blank_lines = True, comment_char = '!'):
"""Returns True if next token in file is a number."""
file_pos = ascii_file.tell()
while True:
if (skip_blank_lines):
file_pos = ascii_file.tell() # will advance file pos to next non-blank line
line = ascii_file.readline()
if len(line) == 0: # end of file
ascii_file.seek(file_pos)
return False
words = line.split()
if len(words) == 0 or words[0][0] == comment_char:
continue # blank line or comment
ascii_file.seek(file_pos) # restore file position whether or not number found
try:
float(words[0])
except Exception: # todo: should only catch a particular exception (type conversion)
return False
else:
return True
[docs]def blank_line(ascii_file):
"""Returns True if the next line contains only white space; False otherwise (including comments)."""
file_pos = ascii_file.tell()
line = ascii_file.readline()
ascii_file.seek(file_pos)
if len(line) == 0:
return True # end of file
words = line.split()
return len(words) == 0
# end of keyword_files module