SOURCE

const s = `
+000001ms INFORMATION: Mon Jan 20 10:33:21 2020


+000000ms INFORMATION: **** LOG FILENAME 2019-1-1-1.log ****
+000000ms INFORMATION: **** SAE J1699-3 Build Revision 16.07.00  (Build Date: Jan 14 2020) ****

+000000ms INFORMATION: **** NOTE: Timestamp on left is from the PC ****
+000000ms INFORMATION: **** NOTE: Timestamp with messages is from the J2534 interface ****

+000000ms INFORMATION: Windows NT/2K/XP (00000000)

+000000ms INFORMATION: Model Year of this vehicle? 2019
+000000ms INFORMATION: How many OBD-II ECUs are on this vehicle?  1
+000000ms INFORMATION: How many reprogrammable OBD-II ECUs are on this vehicle?  1
+000000ms INFORMATION: What type of engine is in this vehicle?  GASOLINE
+000000ms INFORMATION: What type of powertrain is in this vehicle?  CONVENTIONAL
+000000ms INFORMATION: What type of vehicle is being tested?  LIGHT/MEDIUM DUTY VEHICLE
+000000ms INFORMATION: What type of compliance test is to be performed?  China OBD with IUMPR

+000001ms TEST: **** Test 5.1 (MIL bulb check, Engine Off, No DTC set) ****

+003578ms PROMPT: Turn key OFF for 30 seconds or longer, as appropriate for the ECU.
 (Press Enter to continue):  ...

+003074ms PROMPT: Turn key ON with engine OFF. Do not crank engine.
 (Press Enter to continue):  ...


+002868ms PROMPT: Was the MIL ON for at least 15 seconds? (Enter Yes or No):  Y

+000001ms RESULTS: **** Test 5.1 PASSED ****

+000000ms TEST: **** Test 5.2 (Determine Protocol, Ignition On, Engine Off) ****
+000000ms INFORMATION: Firmware Version: N/A
+000000ms INFORMATION: DLL Version: N/A
+000000ms INFORMATION: API Version: N/A
+000000ms INFORMATION: Battery = 11.001V
+000000ms INFORMATION: Checking for OBD on J1850PWM protocol
+000101ms NETWORK: REQ MSG:  J1850PWM 61 6A F1 01 00 
+000000ms INFORMATION: Checking for OBD on J1850VPW protocol
+000100ms NETWORK: REQ MSG:  J1850VPW 68 6A F1 01 00 
+000001ms INFORMATION: Checking for OBD on ISO9141 protocol
+000300ms NETWORK: REQ MSG:  ISO9141 68 6A F1 01 00 
+005001ms INFORMATION: Checking for OBD on ISO14230 Fast Init protocol
+005000ms INFORMATION: Checking for OBD on ISO14230 protocol
+005001ms INFORMATION: Checking for OBD on 500K ISO15765 11 Bit protocol
+000050ms NETWORK: REQ MSG:  ISO15765 00 00 07 DF 01 00 
+000038ms NETWORK: TX MSG:   81040964usec ISO15765 Tx Done Indication 
+000000ms NETWORK: TX MSG:   81040964usec ISO15765 00 00 07 DF 01 00 
+000000ms NETWORK: RX MSG:   81065964usec ISO15765 00 00 07 E8 41 00 FE 3E B8 13 
+000251ms INFORMATION: 1 OBD ECU(s) found
+000000ms INFORMATION: OBD on 500K ISO15765 11 Bit protocol detected
+000000ms INFORMATION: Checking for OBD on 500K ISO15765 29 Bit protocol
+000000ms NETWORK: REQ MSG:  CAN 18 DB 33 F1 02 01 00 00 00 00 00 00 
+003108ms NETWORK: REQ MSG:  ISO15765 00 00 07 DF 01 0C 
+000037ms NETWORK: TX MSG:   81044360usec ISO15765 Tx Done Indication 
+000000ms NETWORK: TX MSG:   81044360usec ISO15765 00 00 07 DF 01 0C 
+000000ms NETWORK: RX MSG:   81069360usec ISO15765 00 00 07 E8 41 0C 00 00 
+000251ms INFORMATION: ECU 7E8  RPM = 0
+000000ms INFORMATION: VerifyVehicleState - Expected State: Off, RPM: 0, Hybrid: No
+000000ms RESULTS: **** Test 5.2 PASSED ****`;

const isContain = (src,str) => {
    return src.indexOf(str) >= 0;
}

const getSubSection = (str) => {
    return str.match(/(\d{1,2}\.\d{1,2})/g)[0];
}

const getSubsectionRes = (str) => {
    return isContain(str,"PASSED");
}

const getHint = (str) => {
    return str.substring(str.indexOf('(') + 1,str.indexOf(')'));
}

const getInfoContent = (str) => {
    return str.substring( str.indexOf(":") + 2 );
}

const decodeDetail = (str,cur,type) => {
    let arr;
    const subsecObj = map.get(cur);
    const hasDefined = subsecObj.hasOwnProperty("arr");
    if(hasDefined) {
        arr = subsecObj["arr"];
    } else {
        arr = [];
    }
    subsecObj["arr"] = [
        ...arr,
        {
            T: type,
            msg: getInfoContent(str)
        }
    ];
}

const map = new Map();
var lines = s.split('\n');

const decode = () => {
    let currentSubSection = '';
    let isSeekingNext = false;

    const alter = (key) => {
        currentSubSection = key;
    }

    return (str) => {
        if( isContain(str,'TEST') ) {
            const key = getSubSection(str);
            alter( key );
            const object = {};
            object.title = getHint(str);
            map.set(key,object);
        } else if ( isContain(str,'RESULTS') ) {
            const res = getSubsectionRes(str);
            map.has(currentSubSection) && (map.get(currentSubSection).res = res);
        } else if (currentSubSection != '') {
            if ( !map.has(currentSubSection) ) return;

           // const infos = map.get(currentSubSection).hasOwnProperty('infos') ? map.get(currentSubSection).infos : [] ;
           // map.get(currentSubSection).infos = [...infos,getInfoContent(str)];
           let type;
           if(isContain(str,"INFORMATION")) { type = "info" } 
           else if (isContain(str,"PROMPT")) { type = "prompt" }
           else if (isContain(str,"NETWORK")) { type = "network" }
           else if (isContain(str,"FAILURE")) {type = "fail"}
           if(!!type) decodeDetail(str,currentSubSection,type)
        }
        
    }
}

const decoder = decode();

lines = lines.filter((line) => line.length > 5);
//   过滤掉含有network的行
//  .filter(line => !isContain(line,'NETWORK'));
lines.forEach(line => decoder(line));

for (let key of map.keys()) {
    console.log(map.get(key));
}
console 命令行工具 X clear

                    
>
console