Untitled

 avatar
unknown
plain_text
21 days ago
17 kB
10
Indexable
import pandas as pd
import re
import numpy as np


# Existing parse_data function
def parse_data(data):
    blocks = data.split("{@BLOCK")  # Split only at {@BLOCK
    global part_number  # Declare it globally at the start of the function

    measurements = []
    platform = "NAN"  # Default to NAN if no platform is found
    part_number = ""  # Default to NAN if no part number is found

    skipped_count = 0  # Track number of skipped lines

    for block in blocks:
        # Ensure the block begins with {@BLOCK
        block = "{@BLOCK" + block if not block.startswith("{@BLOCK") else block

        # Parse the platform if `@BATCH` and `{@BTEST` are found
        if "@BATCH" in block and "{@BTEST" in block:
            batch_line = re.search(r"\{@BATCH[^\{]*\{@BTEST[^\{]*", block)
            if batch_line:
                parts = batch_line.group().split('|')

                # Parse platform (9th split logic)
                if len(parts) >= 15:
                    platform = parts[9].strip()  # 9th split is index 8 (0-based indexing)

                # Parse part number (from index 1 or fallback logic)
                if len(parts) > 1 and parts[1].strip():
                    part_number = parts[1].strip()
                else:
                    for i in range(10, len(parts)):  # Start from the 10th part
                        part = parts[i].strip()
                        if part:
                            part_number = part.split("{@BATCH")[0].strip() if "{@BATCH" in part else part.strip()
                            break

        # Define the pattern to match measurement data
        pattern = r"\{@([\w-]+)\|([^\|]*)\|([^\|]*)\|?([^\|{]*)\{@(LIM2|LIM3)\|([+-]?\d*\.?\d+(?:E[+-]?\d+)?)(?:\|([+-]?\d*\.?\d+(?:E[+-]?\d+)?))?(?:\|([+-]?\d*\.?\d+(?:E[+-]?\d+)?))"
        matches = re.findall(pattern, block)
        a = []

        # Process each match
        for match in matches:
            prefix = match[0]
            if prefix not in {"BLOCK", "BTEST", "BATCH"}:  # Ignore these prefixes
                a.append(prefix)

        # Process `@BTEST` if present
        if "{@BTEST" in block:
            dataBlockSplit = str(block).split('@BTEST')[1].split("{")[0].split("|")

            runs = dataBlockSplit[-1].strip()
            serial = dataBlockSplit[1].strip()
            datatime = dataBlockSplit[3].strip() if len(dataBlockSplit) > 3 else ""

        # Extract test details from `@BLOCK`
        block_matches = re.findall(r"@BLOCK\|([^|]+)\|(\d{2})", block)
        for test_name, pass_fail_code in block_matches:
            # Clean test name
            test_name = re.sub(r'^\d+%', '', test_name)

            pass_fail = "Pass" if pass_fail_code == "00" else "Fail"
            category_matches = re.findall(
                r"@([A-Z-]+)\|(\d)\|([+-]?\d*\.?\d+(?:E[+-]?\d+)?)(?:\|(.+?))?\{", block
            )

            # Extract limits
            lim2_match = re.findall(
                r"@LIM2\|([+-]?\d*\.?\d+(?:E[+-]?\d+)?)\|([+-]?\d*\.?\d+(?:E[+-]?\d+)?)", block
            )
            lim3_match = re.findall(
                r"@LIM3\|([+-]?\d*\.?\d+(?:E[+-]?\d+)?)\|([+-]?\d*\.?\d+(?:E[+-]?\d+)?)\|([+-]?\d*\.?\d+(?:E[+-]?\d+)?)",
                block
            )

            if lim3_match:
                for num in range(len(lim3_match)):
                    category_match = category_matches[num]
                    typeValue = a[num]

                    subtest = category_match[3] if category_match[3] else "None"
                    pass_fail_code = category_match[1]  # Extract pass/fail code (0 or 1)
                    measurement = float(category_match[2])  # Extract measurement

                    pass_fail = "Pass" if pass_fail_code == "0" else "Fail"

                    upper_limit = lower_limit = nominal_value = np.nan

                    nominal_value, upper_limit, lower_limit = map(float, lim3_match[num])
                    # Assuming nominal_value, upper_limit, and lower_limit are defined
                    tol_plus = (upper_limit - nominal_value) / nominal_value * 100 if not np.isnan(
                        nominal_value) else np.nan
                    tol_minus = (lower_limit - nominal_value) / nominal_value * 100 if not np.isnan(
                        nominal_value) else np.nan

                    # Format tol_plus and tol_minus to 1 decimal place
                    tol_plus = round(tol_plus, 1) if not np.isnan(tol_plus) else np.nan
                    tol_minus = round(tol_minus, 1) if not np.isnan(tol_minus) else np.nan

                    # Skip logic: Skip if typeValue is "A-JUM" and measurement is negative
                    if typeValue == "A-JUM" and measurement < 0:
                        skipped_count += 1  # Increment the skip counter
                        continue  # Skip this iteration

                    # Ensure tol_minus is positive (absolute value)
                    tol_minus = abs(tol_minus)

                    measurements.append({
                        "Test Name": test_name,
                        "DateTime": datatime,
                        "Subtest": subtest,
                        "Serial#": serial,
                        "Measure": measurement,

                    })


            elif lim2_match:

                for num in range(len(lim2_match)):
                    if num < len(category_matches):
                        category_match = category_matches[num]
                        # Continue processing
                    else:
                        # Handle mismatch, e.g., skip or log an error
                        print(f"Warning: No matching category for index {num} in block.")
                        continue  # Skip the current iteration
                    typeValue = a[num]
                    subtest = category_match[3] if category_match[3] else "None"
                    pass_fail_code = category_match[1]
                    measurement = float(category_match[2])

                    pass_fail = "Pass" if pass_fail_code == "0" else "Fail"

                    upper_limit = lower_limit = nominal_value = np.nan

                    upper_limit, lower_limit = map(float, lim2_match[num])
                    tol_plus = (upper_limit - nominal_value) / nominal_value * 100 if not np.isnan(
                        nominal_value) else np.nan
                    tol_minus = (lower_limit - nominal_value) / nominal_value * 100 if not np.isnan(
                        nominal_value) else np.nan

                    # Skip logic: Skip if typeValue is "A-JUM" and measurement is negative
                    if typeValue == "A-JUM" and measurement < 0:
                        skipped_count += 1  # Increment the skip counter
                        continue  # Skip this iteration


                    measurements.append({
                        "Test Name": test_name,
                        "DateTime": datatime,
                        "Subtest": subtest,
                        "Serial#": serial,
                        "Measure": measurement,

                    })

    return pd.DataFrame(measurements), skipped_count

# Simple input and print example
def input_and_parse_data():
    # Take input from the user
    data = """
    {@BATCH|000540-||903|1||btest|240221155154||I30704CE243BQ75|OP5|RevA|OP5||
{@BTEST|24052C0G0|00|240221224006|000017|0|all||n|n|240221224023||001|default_SN1
{@PF|1%pins|0|0
}
{@TS|0|000|000|000|1%shorts
}
{@BLOCK|1%c2|00
{@A-CAP|0|+9.940980E-06{@LIM3|+1.050000E-05|+1.363950E-05|+7.360500E-06}}
}
{@BLOCK|1%c13|00
{@A-CAP|0|+9.767915E-06{@LIM3|+1.000100E-05|+1.299130E-05|+7.010701E-06}}
}
{@BLOCK|1%c15|00
{@A-CAP|0|+9.722146E-06{@LIM3|+1.010000E-05|+1.311990E-05|+7.080100E-06}}
}
{@BLOCK|1%c17|00
{@A-CAP|0|+1.070258E-07{@LIM3|+1.000000E-07|+1.299000E-07|+7.010000E-08}}
}
{@BLOCK|1%c18|00
{@A-CAP|0|+1.113787E-07{@LIM3|+1.000000E-07|+1.296000E-07|+7.010000E-08}}
}
{@BLOCK|1%c12|00
{@A-CAP|0|+1.556213E-09{@LIM3|+1.500000E-09|+1.875000E-09|+1.125000E-09}}
}
{@BLOCK|1%c19|00
{@A-CAP|0|+1.546055E-09{@LIM3|+1.500000E-09|+1.875000E-09|+1.125000E-09}}
}
{@BLOCK|1%c20|00
{@A-CAP|0|+1.651738E-09{@LIM3|+1.500000E-09|+1.875000E-09|+1.125000E-09}}
}
{@BLOCK|1%c21|00
{@A-CAP|0|+1.568304E-09{@LIM3|+1.500000E-09|+1.875000E-09|+1.125000E-09}}
}
{@BLOCK|1%l2|00
{@A-JUM|0|+2.836620E+00{@LIM2|+1.000000E+01|+0.000000E+00}}
}
{@BLOCK|1%r12|00
{@A-RES|0|+9.946286E+02{@LIM3|+1.000000E+03|+1.100000E+03|+9.000000E+02}}
}
{@BLOCK|1%r14|00
{@A-RES|0|+9.884425E+02{@LIM3|+1.000000E+03|+1.100000E+03|+9.000000E+02}}
}
{@BLOCK|1%r17|00
{@A-RES|0|+9.923311E+02{@LIM3|+1.000000E+03|+1.100000E+03|+9.000000E+02}}
}
{@BLOCK|1%r3|00
{@A-RES|0|+1.210560E+05{@LIM3|+1.210000E+05|+1.282600E+05|+1.137400E+05}}
}
{@BLOCK|1%r4|00
{@A-RES|0|+2.468543E+05{@LIM3|+2.490000E+05|+2.639400E+05|+2.340600E+05}}
}
{@BLOCK|1%r6|00
{@A-RES|0|+2.870011E+06{@LIM3|+3.000000E+06|+3.300000E+06|+2.700000E+06}}
}
{@BLOCK|1%r8|00
{@A-RES|0|+3.028053E+06{@LIM3|+3.000000E+06|+3.300000E+06|+2.700000E+06}}
}
{@BLOCK|1%r13|00
{@A-RES|0|+3.000838E+06{@LIM3|+3.000000E+06|+3.300000E+06|+2.700000E+06}}
}
{@BLOCK|1%r18|00
{@A-RES|0|+2.980830E+06{@LIM3|+3.000000E+06|+3.300000E+06|+2.700000E+06}}
}
{@BLOCK|1%r15|00
{@A-JUM|0|+2.331387E+00{@LIM2|+1.000000E+01|+0.000000E+00}}
}
{@BLOCK|1%r16|00
{@A-JUM|0|+2.520171E+00{@LIM2|+1.000000E+01|+0.000000E+00}}
}
{@BLOCK|1%d1|00
{@A-ZEN|0|+7.107842E+00{@LIM3|+7.800000E+00|+8.580000E+00|+6.630000E+00}}
}
{@BLOCK|1%d2|00
{@A-ZEN|0|+7.221235E+00{@LIM3|+7.800000E+00|+8.580000E+00|+6.630000E+00}}
}
{@BLOCK|1%u1_clamp_diode|00
{@A-DIO|0|+6.795377E-01|pin_1_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+6.788366E-01|pin_2_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+7.409673E-01|pin_3_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+6.794062E-01|pin_4_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+7.580992E-01|pin_5_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+3.094703E-01|pin_7_gnd{@LIM2|+9.500000E-01|+1.500000E-01}}
{@A-DIO|0|+3.976275E-01|pin_12_gnd{@LIM2|+9.500000E-01|+2.500000E-01}}
{@A-DIO|0|+6.616171E-01|pin_14_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
}
{@BLOCK|1%u2_clamp_diode|00
{@A-DIO|0|+1.796006E-01|pin_1_gnd{@LIM2|+6.500000E-01|+1.000000E-01}}
{@A-DIO|0|+2.157485E-01|pin_2_gnd{@LIM2|+6.500000E-01|+1.000000E-01}}
{@A-DIO|0|+5.671504E-01|pin_4_gnd{@LIM2|+6.500000E-01|+4.000000E-01}}
{@A-DIO|0|+7.377249E-01|pin_5_gnd{@LIM2|+8.500000E-01|+5.000000E-01}}
}
{@BLOCK|1%u3_clamp_diode|00
{@A-DIO|0|+5.671066E-01|pin_11_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+5.819601E-01|pin_15_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+6.283609E-01|pin_20_gnd{@LIM2|+9.500000E-01|+3.500000E-01}}
{@A-DIO|0|+5.839756E-01|pin_22_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+5.835813E-01|pin_23_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+5.844576E-01|pin_28_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+5.836689E-01|pin_29_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+5.847205E-01|pin_33_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+5.877876E-01|pin_34_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+4.068726E-01|pin_41_gnd{@LIM2|+9.500000E-01|+3.000000E-01}}
{@A-DIO|0|+5.843262E-01|pin_42_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
}
{@BLOCK|1%u4_clamp_diode|00
{@A-DIO|0|+2.263519E-01|pin_8_gnd{@LIM2|+6.500000E-01|+1.000000E-01}}
}
{@BLOCK|1%testjet|00
{@TJET|00|0000|1%u1
}
{@TJET|00|0000|1%u3
}
}
{@BLOCK|1%u2|00
{@A-MEA|0|+1.660344E+00|boost{@LIM2|+2.000000E+00|+1.000000E+00}}
{@A-MEA|0|+2.685606E+00|bypass{@LIM2|+3.150000E+00|+1.200000E+00}}
{@D-T|0|384||0|1%u2
}
}
}}


{@BATCH|000540-||903|1||btest|240221093810||I30704CE243BQ75|OP5|RevA|OP5||
{@BTEST|24052C000|00|240221095434|000020|0|all||n|n|240221095454||001|default_SN1
{@PF|1%pins|0|0
}
{@TS|0|000|000|000|1%shorts
}
{@BLOCK|1%c2|00
{@A-CAP|0|+1.015362E-05{@LIM3|+1.050000E-05|+1.363950E-05|+7.360500E-06}}
}
{@BLOCK|1%c13|00
{@A-CAP|0|+9.518092E-06{@LIM3|+1.000100E-05|+1.299130E-05|+7.010701E-06}}
}
{@BLOCK|1%c15|00
{@A-CAP|0|+9.622979E-06{@LIM3|+1.010000E-05|+1.311990E-05|+7.080100E-06}}
}
{@BLOCK|1%c17|00
{@A-CAP|0|+1.063337E-07{@LIM3|+1.000000E-07|+1.299000E-07|+7.010000E-08}}
}
{@BLOCK|1%c18|00
{@A-CAP|0|+1.096751E-07{@LIM3|+1.000000E-07|+1.296000E-07|+7.010000E-08}}
}
{@BLOCK|1%c12|00
{@A-CAP|0|+1.621750E-09{@LIM3|+1.500000E-09|+1.875000E-09|+1.125000E-09}}
}
{@BLOCK|1%c19|00
{@A-CAP|0|+1.615462E-09{@LIM3|+1.500000E-09|+1.875000E-09|+1.125000E-09}}
}
{@BLOCK|1%c20|00
{@A-CAP|0|+1.640613E-09{@LIM3|+1.500000E-09|+1.875000E-09|+1.125000E-09}}
}
{@BLOCK|1%c21|00
{@A-CAP|0|+1.630214E-09{@LIM3|+1.500000E-09|+1.875000E-09|+1.125000E-09}}
}
{@BLOCK|1%l2|00
{@A-JUM|0|+2.828650E+00{@LIM2|+1.000000E+01|+0.000000E+00}}
}
{@BLOCK|1%r12|00
{@A-RES|0|+9.896323E+02{@LIM3|+1.000000E+03|+1.100000E+03|+9.000000E+02}}
}
{@BLOCK|1%r14|00
{@A-RES|0|+9.917171E+02{@LIM3|+1.000000E+03|+1.100000E+03|+9.000000E+02}}
}
{@BLOCK|1%r17|00
{@A-RES|0|+9.903231E+02{@LIM3|+1.000000E+03|+1.100000E+03|+9.000000E+02}}
}
{@BLOCK|1%r3|00
{@A-RES|0|+1.209783E+05{@LIM3|+1.210000E+05|+1.282600E+05|+1.137400E+05}}
}
{@BLOCK|1%r4|00
{@A-RES|0|+2.471828E+05{@LIM3|+2.490000E+05|+2.639400E+05|+2.340600E+05}}
}
{@BLOCK|1%r6|00
{@A-RES|0|+2.884832E+06{@LIM3|+3.000000E+06|+3.300000E+06|+2.700000E+06}}
}
{@BLOCK|1%r8|00
{@A-RES|0|+3.004989E+06{@LIM3|+3.000000E+06|+3.300000E+06|+2.700000E+06}}
}
{@BLOCK|1%r13|00
{@A-RES|0|+2.972655E+06{@LIM3|+3.000000E+06|+3.300000E+06|+2.700000E+06}}
}
{@BLOCK|1%r18|00
{@A-RES|0|+3.003106E+06{@LIM3|+3.000000E+06|+3.300000E+06|+2.700000E+06}}
}
{@BLOCK|1%r15|00
{@A-JUM|0|+2.359659E+00{@LIM2|+1.000000E+01|+0.000000E+00}}
}
{@BLOCK|1%r16|00
{@A-JUM|0|+2.528427E+00{@LIM2|+1.000000E+01|+0.000000E+00}}
}
{@BLOCK|1%d1|00
{@A-ZEN|0|+7.104972E+00{@LIM3|+7.800000E+00|+8.580000E+00|+6.630000E+00}}
}
{@BLOCK|1%d2|00
{@A-ZEN|0|+7.247071E+00{@LIM3|+7.800000E+00|+8.580000E+00|+6.630000E+00}}
}
{@BLOCK|1%u1_clamp_diode|00
{@A-DIO|0|+6.788804E-01|pin_1_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+6.781356E-01|pin_2_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+7.446916E-01|pin_3_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+6.773469E-01|pin_4_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+7.584059E-01|pin_5_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+3.095579E-01|pin_7_gnd{@LIM2|+9.500000E-01|+1.500000E-01}}
{@A-DIO|0|+3.947794E-01|pin_12_gnd{@LIM2|+9.500000E-01|+2.500000E-01}}
{@A-DIO|0|+6.624057E-01|pin_14_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
}
{@BLOCK|1%u2_clamp_diode|00
{@A-DIO|0|+1.801263E-01|pin_1_gnd{@LIM2|+6.500000E-01|+1.000000E-01}}
{@A-DIO|0|+2.163181E-01|pin_2_gnd{@LIM2|+6.500000E-01|+1.000000E-01}}
{@A-DIO|0|+5.671504E-01|pin_4_gnd{@LIM2|+6.500000E-01|+4.000000E-01}}
{@A-DIO|0|+7.378564E-01|pin_5_gnd{@LIM2|+8.500000E-01|+5.000000E-01}}
}
{@BLOCK|1%u3_clamp_diode|00
{@A-DIO|0|+5.667999E-01|pin_11_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+5.827926E-01|pin_15_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+6.286238E-01|pin_20_gnd{@LIM2|+9.500000E-01|+3.500000E-01}}
{@A-DIO|0|+5.840195E-01|pin_22_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+5.832746E-01|pin_23_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+5.836689E-01|pin_28_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+5.830555E-01|pin_29_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+5.837566E-01|pin_33_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+5.873494E-01|pin_34_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
{@A-DIO|0|+4.056457E-01|pin_41_gnd{@LIM2|+9.500000E-01|+3.000000E-01}}
{@A-DIO|0|+5.855968E-01|pin_42_gnd{@LIM2|+9.500000E-01|+4.500000E-01}}
}
{@BLOCK|1%u4_clamp_diode|00
{@A-DIO|0|+2.209188E-01|pin_8_gnd{@LIM2|+6.500000E-01|+1.000000E-01}}
}
{@BLOCK|1%testjet|00
{@TJET|00|0000|1%u1
}
{@TJET|00|0000|1%u3
}
}
{@BLOCK|1%u2|00
{@A-MEA|0|+1.667443E+00|boost{@LIM2|+2.000000E+00|+1.000000E+00}}
{@A-MEA|0|+2.686483E+00|bypass{@LIM2|+3.150000E+00|+1.200000E+00}}
{@D-T|0|384||0|1%u2
}
}
}}

    """

    # Parse the data using the existing function
    df, skipped = parse_data(data)

    # Redirect output to a text file
    output_file = "parsed_output.txt"
    with open(output_file, "w") as f:
        # Write parsed details to the file
        f.write("\nParsed Data:\n")
        f.write(df.to_string(index=False))  # Ensure readable DataFrame output
        f.write(f"\nSkipped Count: {skipped}\n")

    print(f"Output written to {output_file}")


# Call the function to input and parse data
input_and_parse_data()
Leave a Comment