要解析为JSON的数组条目

时间:2016-07-27 04:05:33

标签: javascript arrays json regex

什么是最好的方法 - 正则表达式或其他什么?

我有以下数组:

[
"b1:number/1",
"b1:number/1/chest/85",
"b1:number/1/height/175",
"b1:number/1/hip/90",
"b1:number/1/category/bottoms/size_2/m",
"b1:number/1/category/bottoms/size_1/m",
"b1:number/1/category/bottoms/size_3/s",
]

我需要从入门开始采取品牌b1" b1:" 这应解析如下:

{
    "number": 1,
    "category": "bottoms",
    "height": "175",
    "chest": 85,
    "brand": "b1",
    "hip": 90,
    "size_1": "m",
    "size_2": "m",
    "size_3": "s"
}

编辑: 我只需要解析以" b1:number /"开头的数据。包括像

这样的数据
[
"b1:another/somethingElse", //SHOULD NOT BE CONSIDERED
"b1:number/1",
"b1:number/1/chest/85",
"b1:number/1/height/175",
"b1:number/1/hip/90",
"b1:number/1/category/bottoms/size_2/m",
"b1:number/1/category/bottoms/size_1/m",
"b1:number/1/category/bottoms/size_3/s",
]

6 个答案:

答案 0 :(得分:2)

通常,如果没有对输入格式的良好描述,代码中会有很多假设。以下是我所做的一些值得一提的假设:

  1. 阵列中只有一个“类别”。
  2. 不属于“类别”的属性(即“胸部”,“高度”和“臀部”)均为整数。
  3. 类别下的属性(例如“size_1”等)是字符串。
  4. 具有五个或更多段的任何内容都是输入中的形式(看起来像/ category ///)。 (可选)您可以测试split[2] == 'category'并使用不匹配的字符串执行其他操作。
  5. 每个字符串都以2个字符的前缀开头,即“品牌”。 (可选)您可以获取第一个冒号的所有内容,或仅在某些行中查找该内容。
  6. 以下是代码:

    data = [
        "b1:number/1",
        "b1:number/1/chest/85",
        "b1:number/1/height/175",
        "b1:number/1/hip/90",
        "b1:number/1/category/bottoms/size_2/m",
        "b1:number/1/category/bottoms/size_1/m",
        "b1:number/1/category/bottoms/size_3/s",
    ];
    
    var properties = {};
    properties.brand = data[0].substr(0, 2);
    
    for (var i = 0; i < data.length; i++) {
        var split = data[i].split('/');
        var category = null;
        // Skip entries that don't have any real data
        if (split.length > 2) {
            if (split.length < 6) {
                // e.g. b1:number/1/chest/85
                properties[split[2]] = parseInt(split[3]);
            } else {
                // e.g. b1:number/1/category/bottoms/size_1/m
                properties.category = split[3]; // e.g. bottoms
                properties[split[4]] = split[5]; // e.g. size_1, m
            }
        } else if (split[0].split(':')[1] === 'number') {
            properties.number = split[1];
        }
    }
    
    console.log(properties);
    
    // Output:
    // { brand: 'b1',
    //   number: '1',
    //   chest: 85,
    //   height: 175,
    //   hip: 90,
    //   category: 'bottoms',
    //   size_2: 'm',
    //   size_1: 'm',
    //   size_3: 's' }
    

答案 1 :(得分:1)

我的想法是使用.reduce()来处理数组中的每个元素,并将其值添加到对象中。我/字符上的每个项目.split(),然后测试生成了多少件,以便确定如何处理它。

&#13;
&#13;
function processItem(item) {
  return item.reduce(function(a, v) {
    var parts = v.split("/");
    var b = parts[0].split(":");
    if (b[1] === "number") {
      switch(parts.length) {
        case 2:
          a[b[1]] = parts[1];
          a.brand = b[0];
          break;
        case 4:
          a[parts[2]] = +parts[3]; // note unary plus to convert to number
          break;
        case 6:
          if (!a[parts[2]])
            a[parts[2]] = parts[3];
          a[parts[4]] = parts[5];
          break;
      }
    }
    return a;
  }, {});
}

console.log(processItem([
    "b1:another/somethingElse",
    "b1:number/1",
    "b1:number/1/chest/85",
    "b1:number/1/height/175",
    "b1:number/1/hip/90",
    "b1:another/blah",
    "b1:number/1/category/bottoms/size_2/m",
    "b1:number/1/category/bottoms/size_1/m",
    "b1:number/1/category/bottoms/size_3/s",
]));
&#13;
&#13;
&#13;

答案 2 :(得分:1)

没有任何正则表达式,我可以按照以下方式执行;

var data = [
"b1:number/1",
"b1:number/1/chest/85",
"b1:number/1/height/175",
"b1:number/1/hip/90",
"b1:number/1/category/bottoms/size_2/m",
"b1:number/1/category/bottoms/size_1/m",
"b1:number/1/category/bottoms/size_3/s",
"b1:notnumber/1/category/bottoms/size_4/xs"
],
 dataObj = data.map(e => e.split(":"))
               .map(e => ["brand",e[0]].concat(e[1].indexOf("number") === 0 ? e[1].split("/") :[]))
               .map(e => e.reduce((p,c,i,a) => i%2 === 0 ? (p[c] = a[i+1],p) : p,{}))
               .reduce((p,c) => Object.assign(p,c));
console.log(dataObj);

代码说明:

.map(e => e.split(":"))

这将逐个处理数据数组的每个元素,从":"字符中拆分字符串项,并将每个子字符串放入一个新数组中。因此输入数组将转换为像[["b1","number/1"],["b1","number/1/chest/85"],..., ["b1",notnumber/1/category/bottoms/size_4/xs"]]

这样的2D数组
.map(e => ["brand",e[0]].concat(e[1].indexOf("number") === 0 ? e[1].split("/") :[]))

这是一个非常复杂的部分。每个数据数组项都是由地图仿函数中的e[0]e[1]指定的两个元素的数组。我们将构造一个数组,其中偶数索引处的项目将用于目标对象的属性,奇数索引处的项目将用作值。因此,我们从数组["brand",e[0]]开始,其中e[0]在此特定情况下为"b1"。然后,如果e[1]处的字符串以"number"e[1].indexOf("number") === 0)开头,那么我们将"/"字符拆分为数组。 (e[1].split("/"))并获取"number/1/category/bottoms/size_2/m" - &gt; ["number", "1", "category", "bottoms", "size_2", "m"]但如果它不是以"number"开头,那么我们使用空数组[]。最后,我们将从e[0]e[1]

获得的两个数组进行连接
.map(e => e.reduce((p,c,i,a) => i%2 === 0 ? (p[c] = a[i+1],p) : p,{}))

这是在上述阶段获得的阵列上的标准减少操作。我们正在使用{}的初始值(空对象)进行缩减。偶数索引位置(i%2 === 0)的每个项目都作为属性添加到我们的初始对象中,并且以下属性被添加为此属性p[c] = a[i+1]的值。然后我们返回p来提供reduce迭代的下一个阶段。 ,p) : p

.reduce((p,c) => Object.assign(p,c));

现在我们拥有数据数组中每个项目的对象。我们将它们整合为一体。 Object.assign()是完成这项工作的理想工具。

最后我们在链的末尾返回结果。

答案 3 :(得分:0)

您的输入数据和结果有一个模式,因此这是一个转换操作。由于输入非常简单,您可以简单地使用split函数切割成片段,然后构建输出。

请注意,您还需要进行类型转换和必要的验证。例如,高度是数字,所以不要忘记拨打Number

&#13;
&#13;
function numOrStr(s) {
  return isNaN(s) ? s : Number(s)
}
  
function convert(input) {
  try {
    var arr = input[0].split(':')
    var brand = arr[0]
    arr = arr[1].split('/')

    var result = {
        brand: brand,
        number: Number(arr[1])
    }
    
    input.slice(1).forEach(function(item) {
      item = item.substr((input[0] + '/').length)
      var arr = item.split('/')
      if (arr[0] === 'category') {
        result['category'] = arr[1]
        result[arr[2]] = numOrStr(arr[3])
      } else {
        result[arr[0]] = numOrStr(arr[1])
      }
    })
    
    return result
  } catch (ex) {
    console.error({msg: 'invalid input object', data: input})
  }
}

var input = [
"b1:number/1",
"b1:number/1/chest/85",
"b1:number/1/height/175",
"b1:number/1/hip/90",
"b1:number/1/category/bottoms/size_2/m",
"b1:number/1/category/bottoms/size_1/m",
"b1:number/1/category/bottoms/size_3/s",
]
var output = convert(input)
console.log(output)
&#13;
&#13;
&#13;

答案 4 :(得分:0)

这是纯粹的PHP方法:

<?php

$arr_ = [
"number/1",
"number/1/chest/85",
"number/1/height/175",
"number/1/hip/90",
"number/1/category/bottoms/size_2/m",
"number/1/category/bottoms/size_1/m",
"number/1/category/bottoms/size_3/s",
];
$arr_values = array();

for($i=0; $i <count($arr_);  $i++){

    $arr_data = explode("/", $arr_[$i]);

    for($j=0; $j<count($arr_data); $j++){
        if(!is_null($arr_data[($j + 1)])){
            if(!in_array(array($arr_data[$j] => $arr_data[$j + 1]), $arr_values)){
                array_push($arr_values, array($arr_data[$j] => $arr_data[($j + 1)]));
            }
        }
        $j++;
    }
}
echo json_encode($arr_values);

输出:

[{"number":"1"},{"chest":"85"},{"height":"175"},{"hip":"90"},{"category":"bottoms"},{"size_2":"m"},{"size_1":"m"},{"size_3":"s"}]

答案 5 :(得分:0)

这对正则表达式来说看起来不错。 将数组转换为js对象可以通过以下方式完成:

查找以b1开头的每个数组元素:number并忽略其他数组

\"(((?=b1:number).*[:,/](.*)\/(.*))|(?!>b1:number).*)\"

然后使用最后两组 - 最后一次斜线前后 - 替换

"$3":"$4"

它将生成js对象 - 仍然包裹在数组括号中,并带有空的“属性”

[ "":"", "number":"1", "chest":"85", "height":"175", "hip":"90", "size_2":"m", "size_1":"m", "size_3":"s", ]

然后用卷曲替换数组括号:

"[test]".replace("[", "{").replace("]","}").replace(/"":"",/g, "");;

最后,如果需要js,你需要你的自定义逻辑来处理正确的数据类型。