def search_read(self, expression: 'Any', limit: int = 0) -> 'List[Record]': """ Поиск и считывание записей. :param expression: Поисковый запрос. :param limit: Лимит считываемых записей (0 - нет). :return: Список найденных записей. """ if not self.check_connection(): return [] response = self._search_format_or_read_begin(expression, limit, 'ansi', ALL) if not response.check_return_code(): return [] _ = response.number() result = [] while True: line = response.utf() if not line: break lines = line.split("\x1F") lines = lines[1:] record = Record() record.parse(lines) result.append(record) if limit and len(result) >= limit: break return result
def read_records(self, *mfns: int) -> 'List[Record]': """ Чтение записей с указанными MFN с сервера. :param mfns: Перечень MFN :return: Список записей """ if not self.check_connection(): return [] array = list(mfns) if not array: return [] if len(array) == 1: record = self.read_record(array[0]) return [record] if record else [] lines = self.format_records(ALL, array) result: 'List[Record]' = [] for line in lines: parts = line.split(OTHER_DELIMITER) if parts: parts = [x for x in parts[1:] if x] record = Record() record.parse(parts) if record: record.database = self.database result.append(record) return result
def decode_record(self) -> Record: """ Декодирование в полноценную запись. :return: """ result = Record() result.mfn = self.leader.mfn result.version = self.leader.version result.status = self.leader.status for source in self.fields: target = Field(source.tag) target.headless_parse(source.value) result.fields.append(target) return result
def read_text_record(stream) -> 'Optional[Record]': """ Чтение записи из файла в текстовом обменном формате ИРБИС. :param stream: Файл :return: Запись или None """ result = Record() while True: line: str = stream.readline() if not line: break line = line.strip() if line.startswith(STOP_MARKER): break if not line.startswith('#'): break parts = line[1:].split(':', 1) if len(parts) != 2: break tag = int(parts[0]) text = parts[1][1:] field = Field(tag) field.parse(text) result.fields.append(field) if not result.fields: # Если в записи нет полей, возвращаем None return None return result
def read_iso_record(stream, charset: str = ANSI) -> 'Optional[Record]': """ Чтение записи из файла в формате ISO 2709. :param stream: Файл или файлоподобный объект :param charset: Кодировка :return: Декодированная запись либо None """ # Считываем длину записи marker = stream.read(5) if len(marker) != 5: return None # а затем и ее остаток record_length = parse_int(marker) need = record_length - 5 tail = stream.read(need) if len(tail) != need: return None # Простая проверка, что мы имеем дело с нормальной ISO-записью record = marker + tail if record[record_length - 1] != RECORD_DELIMITER: return None # Превращаем запись в Unicode indicator_length = parse_int(record[10:11]) base_address = parse_int(record[12:17]) # Начинаем собственно конверсию result = Record() # Пошли по полям при помощи справочника directory = MARKER_LENGTH while record[directory] != FIELD_DELIMITER: # если нарвались на разделитель, значит, справочник закончился tag = parse_int(record[directory:directory + 3]) field_length = parse_int(record[directory + 3:directory + 7]) field_offset = parse_int(record[directory + 7:directory + 12]) + \ base_address field = Field(tag) result.fields.append(field) if tag < 10: # фиксированное поле # не может содержать подполей и индикаторов field.value = record[field_offset:field_offset + field_length - 1].decode(charset) else: # поле переменной длины # содержит два однобайтных индикатора # может содержать подполя start = field_offset + indicator_length stop = field_offset + field_length - indicator_length + 1 position = start # ищем значение поля до первого разделителя while position < stop: if record[start] == SUBFIELD_DELIMITER: break position += 1 # если есть текст до первого раздлителя, запоминаем его if position != start: field.value = record[start:position].decode(charset) # просматриваем подполя start = position while start < stop: position = start + 1 while position < stop: if record[position] == SUBFIELD_DELIMITER: break position += 1 subfield = SubField(chr(record[start + 1]), record[start + 2:position].decode(charset)) field.subfields.append(subfield) start = position # переходим к следующему полю в справочнике directory += 12 return result