python学習


import lxml.etree as etree
# 追加・更新関数

class PathManipulator:
    @staticmethod
    def custom_split(xpath, sep='/'):
        result = []
        in_quotes = False
        start = 0

        for i, char in enumerate(xpath):
            if char in ('"', "'"):
                in_quotes = not in_quotes
            elif char in sep and not in_quotes:
                result.append(xpath[start:i])
                start = i + 1

        result.append(xpath[start:])
        return [x for x in result if x]  # 空文字列を除外する

    @staticmethod
    def strncmp(s1, s2, n):
        len1 = len(s1)
        len2 = len(s2)
        min_len = min(len1, len2, n)

        for i in range(min_len):
            if s1[i] != s2[i]:
                return ord(s1[i]) - ord(s2[i])

        if min_len < n:
            return len1 - len2
        else:
            return 0

    @staticmethod
    def split_except_literal(input_string, separator):
        result = []
        temp = ""
        skip_count = 0
        separetor_len = len(separator)
        literal_started = False
        for i, char in enumerate(input_string):
            separator_candidate = PathManipulator.extract_string(
                input_string, i, separetor_len)
            if skip_count > 0:
                skip_count -= 1
                continue
            if char == "'":
                literal_started = not literal_started
                temp += char
            elif PathManipulator.strncmp(separator_candidate, separator, separetor_len) == 0 and not literal_started:
                skip_count = separetor_len - 1
                result.append(temp)
                temp = ""
            else:
                temp += char
        if temp:
            result.append(temp)
        return result

    @staticmethod
    def extract_string(string, start_index, length):
        return string[start_index:start_index + length]


# 追加・更新関数

class XmlManipulator:
    def __init__(self, filepath):
        self.filepath = filepath
        self. parser = etree.XMLParser(remove_blank_text=True)
        self.tree = etree.parse(self.filepath, self.parser)
        self.root = self.tree.getroot()

    def upsert(self, xpath):
        parts = PathManipulator.custom_split(xpath)
        current_element = self.root
        query = "."

        for i, part in enumerate(parts):
            if (part == "."):
                continue

            # タグ名と属性([]をひとかたまりの文字列として扱う)取得する
            tag_name, *attributes_string = PathManipulator.custom_split(part, '[]')
            print(attributes_string)
            print(part + " -> " + tag_name + " -> " + str(attributes_string))
            tag_name = tag_name.strip()
            attributes_string_internal = " ".join(attributes_string).strip()
            attributes_string = ""
            if len(attributes_string_internal) is not 0:
                attributes_string = '[' + attributes_string_internal + ']'

            query = f"./{tag_name}{attributes_string}"
            elements = current_element.xpath(query)

            if not elements:
                # 要素が存在しない場合は新規作成する
                new_element = etree.SubElement(current_element, tag_name)

                # 属性を設定する
                for attribute in PathManipulator.split_except_literal(attributes_string_internal, 'and'):
                    attribute = attribute.strip()
                    key, value = attribute.split('=')
                    key = key.strip("@")
                    new_element.set(key.strip(), value.strip("]['\""))

                current_element = new_element
            else:
                # 要素が存在する場合はその要素を選択する
                print("Found: " + str(len(elements)) +
                      " elements for the given XPath = " + query)
                current_element = elements[0]

        return current_element

    # 削除関数

    def delete(self, xpath):
        elements = self.root.xpath(xpath)
        if len(elements) > 1:
            print("Warning: Multiple elements found for the given XPath = " + xpath)
        elif len(elements) == 1:
            parent = elements[0].getparent()
            parent.remove(elements[0])
        else:
            print("Warning: No elements found for the given XPath = " + xpath)

    def save(self,  filepath):
        # 名前空間を削除して保存する
        for elem in self.root.iter():
            elem.tag = etree.QName(elem).localname
        # インデントを行う
        tree = self.root.getroottree()
        tree.write(filepath, pretty_print=True,
                   encoding='utf-8', xml_declaration=True)


# テスト用のコード
if __name__ == "__main__":
    xml_mod =XmlManipulator('input.xml')
    # 追加・更新のテスト
    # ない場合は新規作成
    xml_mod.upsert(
        "./base[@class='hogeC' and @distName='/aaa/bbb-99/fff-2/ddd-1/']")
    # ない場合は新規作成
    xml_mod.upsert(
        "./base[@class='hogeC' and @distName='/aaa/bbb-99/fff-2/ddd-4/']")
    # ない場合は新規作成
    xml_mod.upsert(
        "./base[@class='hogeC' and @distName='/aaa/eee-99/fff-2/ddd-4/']")
    element = xml_mod.upsert(
        "./base[@class='hogeA' and @distName='/aaa/bbb-99/ccc-5/ddd-1/']/list[@name='hogeList']/p")
    element.text = "hoge1"
    element = xml_mod.upsert(
        "./base[@class='hogeA' and @distName='/aaa/bbb-99/ccc-5/ddd-1/']/list[@name='hogeList']/p")
    element.text = "hoge2"
    element = xml_mod.upsert(
        "./base[@class='hogeA' and @distName='/aaa/bbb-99/ccc-5/ddd-1/']/list[@name='hogeList']/p")
    element.text = "hoge3"
    element = xml_mod.upsert(
        "./base[@class='hogeA' and @distName='/aaa/bbb-99/ccc-5/ddd-1/']/list[@name='hogeList']/p")
    element.text = "hoge4"
    element = xml_mod.upsert(
        "./base[@class='hogeA' and @distName='/aaa/bbb-99/ccc-5/ddd-1/']/list[@name='hogeList']/p")
    element.text = "hoge5"
    xml_mod.upsert("./base[@class='hogeA']")  # ある場合は取得
    # 削除のテスト
    xml_mod.delete("./base[@class='hogeC']")  # 削除する場合
    xml_mod.delete("./base[@class='hogeD']")  # 存在しない場合

    # 保存のテスト
    xml_mod.save( "output.xml")

import csv
import os


class CSVFileManager:
    def __init__(self, file_path, title_row_index=0, primary_keys=None):
        self.file_path = file_path
        self.title_row_index = title_row_index
        self.primary_keys = primary_keys or []
        self.data = self._read_csv()

    def _read_csv(self):
        with open(self.file_path, 'r', newline='') as file:
            reader = csv.reader(file)
            data = list(reader)
        return data

    def save(self, file_path=None):
        file_path = file_path or self.file_path
        with open(file_path, 'w', newline='') as file:
            writer = csv.writer(file)
            writer.writerows(self.data)

    def upsert(self, new_row):
        title_row = self.data[self.title_row_index]
        
        # Check if primary keys are provided
        if not self.primary_keys:
            raise ValueError("Primary keys not specified.")
        
        # Find index of primary key columns
        key_indices = [title_row.index(key) for key in self.primary_keys]
        
        # Check for duplicate primary keys
        for row in self.data[self.title_row_index + 1:]:
            if all(row[idx] == new_row[title_row.index(title)] for idx, title in zip(key_indices, self.primary_keys)):
                raise ValueError("Duplicate primary keys found.")
        
        # Upsert or append the new row
        for idx, row in enumerate(self.data[self.title_row_index + 1:], start=self.title_row_index + 1):
            if all(row[idx] == new_row[title_row.index(title)] for idx, title in zip(key_indices, self.primary_keys)):
                self.data[idx] = new_row
                break
        else:
            self.data.append(new_row)

    def delete(self, key_values):
        title_row = self.data[self.title_row_index]
        
        # Check if primary keys are provided
        if not self.primary_keys:
            raise ValueError("Primary keys not specified.")
        
        # Find index of primary key columns
        key_indices = [title_row.index(key) for key in self.primary_keys]
        
        # Find rows with matching primary keys
        matching_rows = []
        for idx, row in enumerate(self.data[self.title_row_index + 1:], start=self.title_row_index + 1):
            if all(row[idx] == value for idx, value in zip(key_indices, key_values)):
                matching_rows.append(idx)
        
        # Error if no matching rows found
        if not matching_rows:
            print("Warning: No rows found with specified primary keys.")
            return
        
        # Error if multiple matching rows found
        if len(matching_rows) > 1:
            raise ValueError("Multiple rows found with specified primary keys.")
        
        # Delete matching row
        del self.data[matching_rows[0]]


# Example usage:
file_path = "example.csv"
primary_keys = ["ID"]

# Initialize CSVFileManager instance
manager = CSVFileManager(file_path, title_row_index=3, primary_keys=primary_keys)

# Upsert a new row
new_row = ["123", "John Doe", "30"]
manager.upsert(new_row)

# Delete a row
manager.delete(["123"])

# Save changes to file
manager.save()
import pandas as pd
import csv


def custom_split(csv_line, sep=',', strip=True):
    result = []
    in_quotes = False
    start = 0

    for i, char in enumerate(csv_line):
        if char in ('"', "'"):
            in_quotes = not in_quotes
        elif char in sep and not in_quotes:
            csv_value = csv_line[start:i]
            if strip:
                csv_value = csv_value.strip()
            csv_value = remove_outer_quotes(csv_value)
            result.append(csv_value)
            start = i + 1

    csv_value = csv_line[start:]
    if strip:
        csv_value = csv_value.strip()
    result.append(csv_value)
    return [x for x in result if x]  # 空文字列を除外する


def remove_outer_quotes(s):
    if len(s) < 2 or (s[0] != s[-1]) or (s[0] not in ['"', "'"]):
        return s
    elif s.count(s[0]) >= 3:
        return s
    else:
        return s[1:-1]


class CustomCSVParser:
    def __init__(self, file_path, skiprows=3):
        self.data = []
        with open(file_path, 'r') as f:
            lines = f.readlines()
            self.titles = custom_split(lines[skiprows].strip())
            data_lines = lines[skiprows + 1:]
            for line in data_lines:
                line = line.strip()
                if line:
                    row = custom_split(line)
                    self.data.append(row)

    def convertToCsv(self, dn, list_val, param_name, value):
        try:
            dn_index = self.titles.index('DN')
            list_index = self.titles.index('list')
            param_index = self.titles.index('param abbreviated name')
            value_index = self.titles.index('value')

            for row in self.data:
                row_list = row[list_index]
                print(len(row_list), len(list_val), len("''"))
                if row_list == list_val:
                    print("same!")
                if row[dn_index] == dn and row_list == list_val and row[param_index] == param_name:
                    values = row[value_index].split(',')
                    for val_pair in values:
                        key, val = val_pair.split(':')
                        if key == value:
                            return val
                    raise ValueError("Specified value not found in CSV.")
            raise ValueError("Specified combination not found in CSV.")
        except Exception as e:
            return str(e)

    def convertToCom(self, dn, list_val, param_name, value):
        try:
            row = self.data[(self.data['DN'] == dn) & (self.data['list'] == list_val) & (
                self.data['param abbreviated name'] == param_name)]
            if not row.empty:
                if value in row.values[0][4:]:
                    idx = row.values[0][4:].tolist().index(value) + 1
                    return row.columns[idx]
                else:
                    raise ValueError("Specified value not found in CSV.")
            else:
                raise ValueError("Specified combination not found in CSV.")
        except Exception as e:
            return str(e)


# Example usage:
converter = CustomCSVParser("stepdata.csv")
print(converter.convertToCsv("/aaa/bbb-/ccc-/ddd-",
      '', "data_name_1", "111"))  # Output: h2
print(converter.convertToCom("/aaa/bbb-/ccc-/ddd-",
      '', "data_name_1", "h2"))  # Output: 112