You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript字符串解析问题:含空格的key=value对拆分失败

问题描述

需要解析格式类似的LDAP日志行,示例如下:

[16/Nov/2022:12:00:36.523 -0800] BIND RESULT threadID=8 conn=641870 op=11958 msgID=11959 version="3" dn="cn=Directory Manager" authType="SIMPLE" resultCode=0 resultCodeName="Success" qtime=0 etime=0.185 authDN="cn=LDAP Root,cn=Root DNs,cn=config" clientConnectionPolicy="default"

原代码通过空格拆分字符串,遇到authDN这类值含空格且用引号包裹的字段时,会被错误拆分成多个无效条目。原代码如下:

data=str.split(" ");
for (x in data){
switch (x){
case 0:
TimeStamp=data[x] + " " + data[x+1];
break;
case 1:
break;
case 2:
entryType=data[x] + " " + data[x+1];
break;
case 3:
break;
default:
entry.setAttribute(data[x].toString().split('=')[0],data[x].toString().split('=')[1]);

break;
}
}

解决方案1:正则表达式匹配(推荐)

用正则直接匹配所有合法的key=value对,不管值是否带引号和空格。正则能同时处理两种值格式:不带引号的纯字符值,以及带双引号包裹的含空格值。

实现代码

const logLine = '[16/Nov/2022:12:00:36.523 -0800] BIND RESULT threadID=8 conn=641870 op=11958 msgID=11959 version="3" dn="cn=Directory Manager" authType="SIMPLE" resultCode=0 resultCodeName="Success" qtime=0 etime=0.185 authDN="cn=LDAP Root,cn=Root DNs,cn=config" clientConnectionPolicy="default"';

// 提取时间戳和操作类型
const headerMatch = logLine.match(/^\[(.*?)\]\s+(.*?)\s+/);
const timeStamp = headerMatch[1];
const entryType = headerMatch[2];

// 匹配所有key=value对
const kvRegex = /(\w+)=("([^"]+)"|([^\s"]+))/g;
const kvPairs = logLine.match(kvRegex) || [];

const entry = {};
kvPairs.forEach(pair => {
  // 拆分key和value部分,只拆一次等号
  const [key, valuePart] = pair.split('=', 2);
  // 去掉值的引号(如果有)
  const value = valuePart.startsWith('"') ? valuePart.slice(1, -1) : valuePart;
  entry[key] = value;
  // 如果你需要用setAttribute方法,替换成 entry.setAttribute(key, value)
});

console.log('时间戳:', timeStamp);
console.log('操作类型:', entryType);
console.log('解析结果:', entry);

正则说明

  • (\w+): 匹配key部分(字母、数字、下划线组成)
  • = : 匹配分隔用的等号
  • ("([^"]+)"|([^\s"]+)): 匹配两种值格式:
    • "([^"]+)": 匹配带双引号的值,捕获引号内所有非引号字符
    • ([^\s"]+): 匹配不带引号的值,捕获非空格、非引号的连续字符
  • /g: 全局匹配所有符合条件的key=value对

解决方案2:状态机解析(适合复杂场景)

如果日志格式存在更复杂的情况(比如值内有转义引号),状态机逐字符解析的方式会更灵活,能应对各种边界情况。

实现代码

function parseLogLine(logLine) {
  const result = {
    timeStamp: '',
    entryType: '',
    attributes: {}
  };

  let index = 0;
  const len = logLine.length;

  // 解析时间戳:从[开始到]结束
  if (logLine[index] === '[') {
    index++;
    while (index < len && logLine[index] !== ']') {
      result.timeStamp += logLine[index];
      index++;
    }
    index++; // 跳过闭合的]
  }

  // 解析操作类型:跳过空格,直到遇到第一个key=value开头
  while (index < len && logLine[index] === ' ') index++;
  let entryType = '';
  while (index < len && !/\w+=/.test(logLine.slice(index, index + 5))) {
    entryType += logLine[index];
    index++;
  }
  result.entryType = entryType.trim();

  // 解析key=value对
  let currentKey = '';
  let currentValue = '';
  let inQuotes = false;
  let state = 'key'; // key: 收集key阶段; value: 收集value阶段

  while (index < len) {
    const char = logLine[index];

    if (state === 'key') {
      if (char === '=') {
        state = 'value';
      } else if (char !== ' ') {
        currentKey += char;
      }
    } else if (state === 'value') {
      if (char === '"') {
        inQuotes = !inQuotes;
      } else if (char === ' ' && !inQuotes) {
        // 结束当前value,存入结果
        result.attributes[currentKey] = currentValue.trim();
        currentKey = '';
        currentValue = '';
        state = 'key';
      } else {
        currentValue += char;
      }
    }

    index++;
  }

  // 保存最后一组key=value
  if (currentKey) {
    result.attributes[currentKey] = currentValue.trim();
  }

  return result;
}

// 使用示例
const logLine = '[16/Nov/2022:12:00:36.523 -0800] BIND RESULT threadID=8 conn=641870 op=11958 msgID=11959 version="3" dn="cn=Directory Manager" authType="SIMPLE" resultCode=0 resultCodeName="Success" qtime=0 etime=0.185 authDN="cn=LDAP Root,cn=Root DNs,cn=config" clientConnectionPolicy="default"';
const parsedResult = parseLogLine(logLine);
console.log(parsedResult);

状态机优势

  • 可轻松扩展处理转义引号(如\")
  • 对日志格式的微小变化兼容性更强
  • 逻辑直观,不需要依赖正则的复杂写法

内容的提问来源于stack exchange,提问作者Billv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 08:35:20