
# 提取字符串动态键值对
本文档介绍如何使用不同方案提取字符串键值对。
#### 常用方案比较
字符串动态键值对提取分为关键字提取、值提取、关键字加工和值加工，常用方案为采用e_kv函数、e_kv_delimit函数和e_regex函数等。不同提取场景的三种方案如下：
| **方案**       | **关键字提取**          | **值提取**                    | **关键字加工** | **值加工**    |
|:---|:---|:---|:---|:---|
| e_kv         | 使用特定正则表达式          | 支持默认的字符集、特定分隔符或者带(、)或（"）分隔 | 支持前后缀     | 支持文本escape |
| e_kv_delimit | 使用特定正则表达式          | 使用分隔符                      | 支持前后缀     | 默认无        |
| e_regex      | 组合自定义正则表达式和默认字符集过滤 | 完全自定义                      | 自定义       | 自定义        |
   
大部分键值对的提取使用e_kv函数并配置特定参数就可以很好地满足，尤其是带括字符和反斜杠需要提取并转义时。其他复杂或高级的场景可以用e_regex函数来提取。部分特定场景下的键值对使用e_kv_delimit函数会更简单。
#### 关键字提取
1. 示例1 以k1: q=asd\&a=1\&b=2\&__1__=3日志为例，如果要对该格式的日志作为关键字和值提取，三种方案如下：
   - e_kv函数
     - 原始日志
       ```
       {
           "k1":"q=asd&a=1&b=2&__1__=3"
       }
       ```
       
     
     - 加工规则
       ```
       e_kv("k1")
       ```
       
     
     - 加工结果
       ```
       {
       "q": "asd",
       "a": 1,
       "b": 2,
       "k1": "q=asd&a=1&b=2&__1__=3",
       "__1__": 3
       }
       ```
       
      
   
   - e_kv_delimit函数
     - 原始日志
       ```
       {
           "k1":"q=asd&a=1&b=2&__1__=3"
       }
       ```
       
     
     - 加工规则
       ```
       # 以&分隔键值后,用&分隔提取出关键字
       e_kv_delimit("k1", pair_sep=r"&")
       ```
       
     
     - 加工结果
       ```
       {
       "q": "asd",
       "a": 1,
       "b": 2,
       "k1": "q=asd&a=1&b=2&__1__=3",
       "__1__": 3
       }
       ```
       
      
   
   - e_regex函数
     - 原始日志
       ```
       {
           "k1":"q=asd&a=1&b=2&__1__=3"
       }
       ```
       
     
     - 加工规则
       ```
       # 自行指定字符集提取关键字和值
       e_regex("k1",r"(\w+)=([a-zA-Z0-9]+)",{r"\1": r"\2"})
       ```
       
     
     - 加工结果
       ```
       {
       "q": "asd",
       "a": 1,
       "b": 2,
       "k1": "q=asd&a=1&b=2&__1__=3",
       "__1__": 3
       }
       ```
       
      
    
2. 示例2 以content:k1=v1\&k2=v2?k3:v3为例，需要特定正则提取关键字，方案如下：
   - e_kv_delimit函数
     - 原始日志
       ```
       {
           "content":"k1=v1&k2=v2?k3:v3"
       }
       ```
       
     
     - 加工规则
       ```
       e_kv_delimit("content",pair_sep=r"&?",kv_sep="(?:=|:)")
       ```
       
     
     - 加工结果
       ```
       {
       "k1": "v1",
       "k2": "v2",
       "k3": "v3",
       "content": "k1=v1&k2=v2?k3:v3"
       }
       ```
       
      
   
   - e_regex函数
     - 原始日志
       ```
       {
           "content":"k1=v1&k2=v2?k3:v3"
       }
       ```
       
     
     - 加工规则
       ```
       e_regex("content",r"([a-zA-Z0-9]+)[=|:]([a-zA-Z0-9]+)",{r"\1": r"\2"})
       ```
       
     
     - 加工结果
       ```
       {
       "k1": "v1",
       "k2": "v2",
       "k3": "v3",
       "content": "k1=v1&k2=v2?k3:v3"
       }
       ```
       
      
    
 
#### 值提取
- 动态键值对之间以及关键字与值之间有明确标识，如a=b或a="cxxx"日志格式的，推荐用e_kv函数，示例如下。
  - 原始日志
    ```
    {
        "content":"k=\"helloworld\",the change world, k2=\"good\""
    }
    ```
    
  
  - 加工规则 这种情况下使用e_kv函数，提取内容不包括the change world：
    ```
    e_kv("content")
    # e_regex函数写法
    e_regex("content",r"(\w+)=\"(\w+)",{r"\1": r"\2"})
    ```
    
  
  - 加工结果：提取后的日志为：
    ```
    {
    "k2": "good",
    "k": "helloworld",
    "content": "k=\"helloworld\",the change world, k2=\"good\""
    }
    ```
    
   
- 对带"的日志格式content:k1="v1=1"\&k2=v2?k3=v3，推荐使用e_kv函数进行提取，例如：
  - 原始日志
    ```
    {
        "content":"k1=\"v1=1\"&k2=v2?k3=v3"
    }
    ```
    
  
  - 加工规则
    ```
    e_kv("content",sep="=", quote="'")
    ```
    
  
  - 加工结果 处理后日志为：
    ```
    {
    "k1": "v1=1",
    "k2": "v2",
    "k3": "v3",
    "content": "k1=\"v1=1\"&k2=v2?k3=v3"
    }
    ```
    
   
 
#### 关键字加工
- e_kv函数和e_kv_delimit函数都可以通过prefix="", suffix=""对关键字和值进行加工。
  - 原始日志
    ```
    {
        "content":"q=asd&a=1&b=2"
    }
    ```
    
  
  - 加工规则(各语句分开执行，功能相同)
    ```
    e_kv("content", sep="=", quote='"', prefix="start_", suffix="_end")
    e_kv_delimit("content", pair_sep=r"&", kv_sep="=", prefix="start_", suffix="_end")
    e_regex("content",r"(\w+)=([a-zA-Z0-9]+)",{r"start_\1_end": r"\2"})
    ```
    
  
  - 加工结果 加工后的数据都是关键字加工形式，如下：
    ```
    {
    "start_b_end": 2,
    "start_a_end": 1,
    "start_q_end": "asd",
    "content": "q=asd&a=1&b=2"
    }
    ```
    
   
- e_regex函数对关键字加工的能力更强，例如：
  - 加工规则
    ```
    e_regex("content",r"(\w+)=([a-zA-Z0-9]+)",{r"\1_\1": r"\2"})
    ```
    
  
  - 加工结果 加工后的数据都是关键字加工形式，如下：
    ```
    {
    "q_q": "asd",
    "a_a": 1,
    "b_b": 2,
    "content": "q=asd&a=1&b=2"
    }
    ```
    
   
 
#### 值加工
日志格式为k1:"v1\\"abc"形式， 同时值加工的内容存在有双引号符号的情形，使用e_kv函数可正常进行提取。
- 原始日志
  ```
  """
  这里的\只是普通的符号，不是转义符
  """
  {
      "content":"k1:\"v1\\\"abc\", k2:\"v2\", k3: \"v3\""
  }
  ```
  
- 加工规则：
  ```
  e_kv("content",sep=":", quote='"')
  ```
  
- 加工结果 提取后的日志为：
  ```
  {
  "k1": "v1\\",
  "k2": "v2",
  "k3": "v3",
  "content": "k1:\"v1\\\"abc\", k2:\"v2\", k3: \"v3\""
  }
  ```
  
 
