How to fix invalid JSON with RegExp in Javascript? - javascript

This is what I've tried
// input
let input = "{id: 1, name: apple, qty: 2, colors: [{id: 1, hex: #f95}], store: {id: 1, name: Apple Store}}"
let result = input.replace((/([\w]+)(:)/g), "\"$1\"$2");
// {"id": 1, "name": apple, "qty": 2, "colors": [{"id": 1, "hex": #f95}], "store": {"id": 1, "name": Apple Store}}
And then I just replace it like, replaceAll(': ', ': "'). I think it's not good practice to resolve it, may there is someone who can help me with this problem, thank you so much.

You can convert the stated string that looks almost like an object into an actual JavaScript object with the following assumptions:
keys are composed of alphanumeric and underscores chars
values are treated as numbers if they have the format of a number, e.g. an optional minus sign, followed by digits with optional .
values are treated as a string unless it has the form of a number, or start with [ (array) or { (object)
string values may not contain , or }
const input = "{id: 1, name: apple, qty: 2, colors: [{id: 1, hex: #f95}], store: {id: 1, name: Apple Store}}";
const regex1 = /([,\{] *)(\w+):/g;
const regex2 = /([,\{] *"\w+":)(?! *-?[0-9\.]+[,\}])(?! *[\{\[])( *)([^,\}]*)/g;
let json = input
.replace(regex1, '$1"$2":')
.replace(regex2, '$1$2"$3"')
let result = JSON.parse(json);
console.log(JSON.stringify(result, null, ' '));
Output:
{
"id": 1,
"name": "apple",
"qty": 2,
"colors": [
{
"id": 1,
"hex": "#f95"
}
],
"store": {
"id": 1,
"name": "Apple Store"
}
}
Explanation of regex1:
([,\{] *) -- capture group 1: , or {, followed by optional spaces
(\w+) -- capture group 2: 1+ word chars (alphanumeric and underscore)
: -- literal :
replace '$1"$2":' -- capture group 1, followed by capture group 2 enclosed in quotes, followed by colon
Explanation of regex2:
([,\{] *"\w+":) -- capture group 1: , or {, followed by optional spaces, quote, 1+ word chars, quote, colon
(?! *-?[0-9\.]+[,\}]) -- negative lookahead for optional spaces, a number, followed by , or }
(?! *[\{\[]) -- negative lookahead for optional spaces, followed by { or [
( *) -- capture group 2: optional spaces
([^,\}]*) -- capture group 3: everything that is not a , or }
replace '$1$2"$3"' -- capture group 1, followed by capture group 2, followed by capture group 3 enclosed in quotes
Learn more about regex: https://twiki.org/cgi-bin/view/Codev/TWikiPresentation2018x10x14Regex

Thanks for all answers, I tried this way and its works
class FixJson {
constructor() {
this.run = (json) => {
const fixDataType = (json) => {
for (const key in json) {
if (json.hasOwnProperty(key)) {
const value = json[key];
if (typeof value === 'object') {
fixDataType(value);
} else if (value === 'true' || value === 'false') {
json[key] = value === 'true';
} else if (!isNaN(value)) {
json[key] = Number(value);
}
}
}
return json;
}
// use the replace function to add double quotes around the property names
const fixedJson = json.replace(/([a-zA-Z0-9!##\$%\^\&*\)\(+=._-]+)/g, '"$1"');
// use the JSON.parse function to parse the fixed JSON string into a JavaScript object
const obj = JSON.parse(fixedJson.replaceAll('" "', ' '));
// fix json data type, and return the result
return fixDataType(obj)
}
}
}
const fix = new FixJson()
let result = fix.run("<your_invalid_json>")

Related

Parsing text using regex javascript

guys i am stuck while parsing following text into object. I have created two separate regex but i want to make only one. Below i am posting sample text as well as my following regex pattern.
PAYER:\r\n\r\n MCNA \r\n\r\nPROVIDER:\r\n\r\n MY KHAN \r\n Provider ID: 115446397114\r\n Tax ID: 27222193992\r\n\r\nINSURED:\r\n\r\n VICTORY OKOYO\r\n Member ID: 60451158048\r\n Birth Date: 05/04/2008\r\n Gender: Male\r\n\r\nCOVERAGE TYPE:\r\n\r\n Dental Care
REGEX:
re = new RegExp('(.*?):\r\n\r\n(.*?)(?:\r\n|$)', 'g');
re2 = new RegExp('(.*?):(.*?)(?:\r\n|$)', 'g');
Expected result:
{
payer: 'MCNA',
provider: 'MY KHAN'
}
This turns your input into an object that contains all key/value pairs:
const input = 'PAYER:\r\n\r\n MCNA \r\n\r\nPROVIDER:\r\n\r\n MY KHAN \r\n Provider ID: 115446397114\r\n Tax ID: 27222193992\r\n\r\nINSURED:\r\n\r\n VICTORY OKO\r\n Member ID: 60451158048\r\n Birth Date: 05/04/2009\r\n Gender: Male\r\n\r\nCOVERAGE TYPE:\r\n\r\n Dental Care';
let result = Object.fromEntries(input
.replace(/([^:]+):\s+([^\n\r]+)\s*/g, (m, c1, c2) => c1.toLowerCase() + '\r' + c2 + '\n')
.split('\n')
.filter(Boolean)
.map(item => item.trim().split('\r'))
);
console.log(result);
Output:
{
"payer": "MCNA",
"provider": "MY KHAN",
"provider id": "115446397114",
"tax id": "27222193992",
"insured": "VICTORY OKO",
"member id": "60451158048",
"birth date": "05/04/2009",
"gender": "Male",
"coverage type": "Dental Care"
}
Explanation:
Object.fromEntries() -- convert a 2D array to object, ex: [ ['a', 1], ['b', 2] ] => {a: 1, b: 2}
.replace() regex /([^:]+):\s+([^\n\r]+)\s*/g -- two capture groups, one for key, one for value
replace action c1.toLowerCase() + '\r' + c2 + '\n' -- convert key to lowercase, separate key/value pairs with newline
.split('\n') -- split by newline
.filter(Boolean): -- remove empty items
.map(item => item.trim().split('\r')) -- change array item to [key, value], e.g. change flat array to 2D array
You could add one more filter after the .map() to keep only keys of interest.

Regex for substring on NodeJS using pinch.js

I am modifying JSON files/Javascript object using Pinch library: https://github.com/Baggz/Pinch
In this example, pinch() with regex parameter /id/ modifies ALL the id values to 321.
What I want to do is be able to change the value of all ids but only for a specific "Requestor", based on a parameter (requestorToChange). Let's say "RequestorX". How do I write the regex for it?
var sample = {
"RequestorX":
[{
user: {
id: '123'
},
request: {
id: '456'
},
book: {
id: '789'
}
}],
"RequestorY":
[{
user: {
id: '111'
},
request: {
id: '222'
},
book: {
id: '333'
}
}]
};
const requestorToChange = 'RequestorX'
pinch(sample, /id/, function(path, key, value) {
return '321';
});
console.log(JSON.stringify(sample))
I know that one option is to just do:
pinch(sample['RequestorX'], /id/, function(path, key, value) {
return '321';
});
But I need to be able to do it via the regex field since in reality, I will be manipulating deeply nested JSON files.
The explanation on the GitHub page is a bit sparse, but basically you start with the dot notation replacement style and replace the variable parts with regex patterns whilst adhering to the rules of JS regular expressions.
So, in your case, a dot notation pattern 'RequestorX[0].user.id'
becomes a regex like /RequestorX\[0\]\.(user|request|book)\.id/
Somes notes:
first we have to escape the square brackets because those have special meaning in regex
next, we also have to escape the . to use it as dot notation symbol
we use a group with alternations to replace the id on all of them
I tried to use new RegExp instead of the /../ notation to create a regex Object to add your constant to the pattern, unfortunately only the first item is replaced in this case, probably a bug...
pinch(sample, new RegExp(requestorToChange +'\[0\]\.(user|request|book)\.id'), '321');
Sample code (the SO code snippet outputs some extra gibberish about RequestorY, ignore it)
var sample = {
"RequestorX": [
{
"user": {
"id": "123"
},
"request": {
"id": "456"
},
"book": {
"id": "789"
}
}
],
"RequestorY": [
{
"user": {
"id": "123"
},
"request": {
"id": "456"
},
"book": {
"id": "789"
}
}
]
}
const requestorToChange = 'RequestorX';
//var result = pinch(sample, 'RequestorX[0].user.id', '321'); //replace the user id of RequestorX with dot notation
var result = pinch(sample, /RequestorX\[0\]\.(user|request|book)\.id/, '321');
//var result = pinch(sample, new RegExp(requestorToChange +'\[0\]\.(user|request|book)\.id'), '321');
console.log(JSON.stringify(result));
<script src="https://cdn.jsdelivr.net/npm/pinch#0.1.3/src/pinch.js"></script>
Alas, JSON + regex sounds a bit weird but the tool looks legit.

Match and replace all strings inside object with strings from another object

I have an object which contains UTF-8 characters as strings - I figured I could make another object with the list of characters and how I'd like to replace them?
The Data Object
var data = [
{"my_string":"ABC & I","value":13,"key":8},
{"my_string":"A “B” C","value":12,"key":9}
];
The Replacement Object
var str_to_change = [
{value: "&", replace: "&"},
{value: "“", replace: ""},
{value: "”", replace: ""}
];
I'd like to write a function where anytime a str_to_change.value is seen inside data.my_string, replace it with str_to_change.replace
Is this the best way to go about changing various character strings, and how would I execute this? I found this: Iterate through object literal and replace strings but it's a little more complex since I'm not just replacing with a singular string.
Rather than an array of objects, consider constructing just a single object with multiple keys:
const replacements = {
"&": "&",
"“": '',
"”": '',
};
Then, with the keys, escape characters with a special meaning in regular expressions, join the keys by |, construct a regular expression, and have a replacer function access the matched substring as a property of the replacements object:
var str_to_change = [{value: "&", replace: "&"},
{value: "“", replace: ""},
{value: "”", replace: ""}];
const replacements = Object.fromEntries(str_to_change.map(({ value, replace }) => [value, replace]));
const escape = s => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
const pattern = new RegExp(Object.keys(replacements).map(escape).join('|'), 'gi');
var data = [{
"my_string": "ABC & I",
"value": 13,
"key": 8
},
{
"my_string": "A “B” C",
"value": 12,
"key": 9
}];
const mappedData = data.map(({ my_string, ...rest }) => ({
...rest,
my_string: my_string.replace(
pattern,
prop => replacements[prop]
)
}));
console.log(mappedData);

How to filter UK postcodes

I'm trying to match the first part of a UK postcode to those that I have held in a JSON file. I'm doing this in Vue.
At the moment I have managed to match the postcode if it has 2 letters that match, but some UK postcodes do not start with 2 letters, some just have the one and this is where it fails.
See here for full code
https://codesandbox.io/s/48ywww0zk4
Sample of JSON
{
"id": 1,
"postcode": "AL",
"name": "St. Albans",
"zone": 3
},
{
"id": 2,
"postcode": "B",
"name": "Birmingham",
"zone": 2
},
{
"id": 3,
"postcode": "BA",
"name": "Bath",
"zone": 5
}
let postcodeZones = this.postcodeDetails.filter(
pc => pc.postcode
.toLowerCase()
.slice(0, 2)
.indexOf(this.selectPostcode.toLowerCase().slice(0, 2)) > -1
);
Can anyone help me find (for example) 'B' if I type B94 5RD & 'BA' if I type BA33HT?
You can use a regular expression that matches the alphabetical letters at the start of a string.
function getLettersBeforeNumbers( postcode ) {
return postcode.match( /^[a-zA-Z]*/ )[0];
}
let a = getLettersBeforeNumbers( 'B94 5RD' );
let b = getLettersBeforeNumbers( 'bA33HT' );
let c = getLettersBeforeNumbers( '33bA33HT' );
console.log( a, b, c );
/** EXPLANATION OF THE REGEXP
/ ^[a-zA-Z]* /
^ = anchor that signifies the start of the string
[ ... ] = select characters that are equal to ...
a-z = all characters in the alphabet
A-Z = all capatilised characters in the alphabet
* = zero or more occurances
**/
PS: You can just use the .match( /^[a-zA-Z]*/ )[0]; on your string.

How to trim the last one or last two characters of a string

I have an object with a bunch of strings:
[
{
date: "03/12/2014",
name: "mr blue",
title: "math teacher -"
},
{
date: "04/02/2015",
name: "mrs yellow",
title: "chemistry teacher"
},
{
date: "11/04/2014",
name: "mrs green",
title: "chemistry teacher - "
},
]
How can i strip the - from the title field if that string contains a -.
I know a can perform a slice/subtring:
var myvalue = myobject.title.substring(0, myobject.title.length-1);
However this will apply for all cases, and not just the ones that contain the -
Use replace:
var myvalue = myobject.title.replace(/\s*-\s*$/,'');
Bonus: with this regular expression only a dash at the end will be removed (along with the spaces around).
var title = 'math teacher -';
title = title.replace('-', '').trim();
document.write(title);
Update
Above will fail if title has dashes in the middle. Therefore, using lastIndexOf you can do
title = title.substring(0,oldString.lastIndexOf("-")).trim;

Categories