要解析为JSON的数组条目

问题描述:

什么是最好的方法 - 正则表达式或其他东西?要解析为JSON的数组条目

我有以下阵列:

[ 
"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", 
] 
+1

我认为你的意思是JavaScript对象而不是“JSON对象”。除非你打算解析这个并把它放在一个.json文件中。 –

+0

“胸”,“身高”,“臀围”和“类别”是第三级唯一的可能性吗?并且胸部/身高/臀部总是出现在*类别信息之前*你的示例数组很小。真实数据中有多少元素? – nnnnnn

+0

在一个特定的api响应中,我只需要解析这个上面的数组。它仅在不同的API调用的值上有所不同。基本上结构是相似的。 @nnnnnn – Nisha

我的想法是使用.reduce()处理阵列中的每个元素,并添加其值的一个对象。 I .split()/字符上的每个项目,然后测试生成的片断数量以确定如何处理它。

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", 
 
]));

+0

不错!不过,请注意在问题中添加“品牌”。 – smarx

+0

@smarx - 谢谢。是的,总是似乎有一些额外的要求,最初没有提到...我会编辑... – nnnnnn

+0

@Nisha - 我添加了一个if测试来检查数字。任何进一步的变化将留给读者作为练习... – nnnnnn

一般来说,没有一个很好的输入格式描述,会有很多假设烘焙到代码中。以下是我所做的一些值得大声呼吁的假设:

  1. 数组中只有一个“类别”。
  2. 不属于“类别”(即“胸部”,“身高”和“臀部”)的属性意味着整数。
  3. 类别下的属性(例如“size_1”等)是字符串。
  4. 具有五个或更多段的任何内容都是输入形式(看起来像/ category ///)。或者,您可以测试split[2] == 'category'并使用不匹配的字符串执行其他操作。
  5. 每个字符串以2个字符的前缀开头,即“品牌”。或者,您可以抓住一切,直到第一个冒号,或者只在特定行上寻找。

下面的代码:

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' } 
+0

属性“数字”? – Nisha

+0

非常接近要求..但是如果像“b1:somethingElse/abc”这样的额外数据出现,数字会出错。我们可以在那里使用正则表达式来表示“数字”,并放弃所有不以“b1:数字/”开头的其他数字? – Nisha

输入数据和结果有一个模式,所以这是一个变换操作。由于输入非常简单,您可以简单地使用split函数将其切割成小块,然后构建输出。

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

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)

这是纯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); 

OUTPUT:

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

我想JS。抱歉不是php。 – Nisha

没有任何的正则表达式我如下可能做到这一点;

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"]]

.map(e => ["brand",e[0]].concat(e[1].indexOf("number") === 0 ? e[1].split("/") :[])) 

这是sligtly复杂的部分。每个数据数组项是由映射函子内的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"["number", "1", "category", "bottoms", "size_2", "m"]但是如果它不以"number"开始,那么我们使用空数组[]。最后,我们从concatanate 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()是这项工作的理想工具。

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

+0

修改了代码以处理“不数字条件”。我希望它很好。 @Nisha – Redu

+0

我的{品牌:'b1'}作为你的代码的回应。是错过了什么? – Nisha

+0

奇怪应该可以正常工作......在Chrome,Opera和FF上看起来工作正常。你使用的是什么浏览器..? @Nisha – Redu

这对于正则表达式看起来很不错。 转换您的阵列到JS对象可以用这个来完成:

查找开始B1每个数组元素:数量,而忽略其他

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

然后用最后2组 - 前和最后一个斜线后 - 为取代

"$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, "");; 

而且finaly您需要自定义的逻辑来处理,如果需要,甚至在适当的JS数据类型。

+0

好的,查看我编辑的答案 –