Multiple regular expression pattern on a single input

Viewed 47

Hi I am new to this and need help extracting address from the following string.

"Street name: Main St\r\nHouse number: 3250\r\nCity: Corona\r\nState: CA\r\nPostal code: 92882\r\nCountry: United States"

Currently I am using multiple patterns to extract each element and then concat it but I want to know if i can do it in one shot.

I am using "City\:(.*)" to extract Corona, "House number\:(.*)" to extract 3250 and then combining multiple strings to form the address "1 Main St, Corona CA 92882"

Is there a way I can extract and contact in a single regular expression to get the desired results?

4 Answers

We can use match(), capture all key:value pairs, then build a map of keys and values.

var input = "Street name: Main St\r\nHouse number: 3250\r\nCity: Corona\r\nState: CA\r\nPostal code: 92882\r\nCountry: United States";
var map = {};
input.match(/\w+(?: \w+)*: \w+(?: \w+)*(?:\r\n|$)/g)
     .forEach(x => map[x.split(":")[0]] = x.split(":")[1].trim());
var address = map["House number"] + " " + map["Street name"] + ", " +
              map["City"] + " " + map["State"] + " " + map["Country"];
console.log(address);

What You Can Do

In most cases, you can get away with compounding regular expressions by matching anything in between until the next expression. This can be accomplished by using the following little Regex:

.*?

Explaining the Regular Expression

.*? basically means:

  • Any character (.)
  • repeated any number of times, including zero (*)
  • until the first chance it has to not be repeated (?)

The way your regular expressions are currently written, you're going to have a little bit of trouble because the way you're matching content after each field is to use the first two parts of this trick to match anything, which will "greedily" match until there's nothing left to match.

This is why '*' is referred to as the 'greedy' quantifier, and '?' is referred to as the lazy quantifier. By combining the two, you're basically saying "match as much as you can, until there's something else to match"

So, the short answer to your question is probably:

Replace every instance of .* with .*?.

Additional Tips

Named Groups

When you're matching many things, you should probably consider using named groups:

Street name:(?<Street>.*?)House number:(?<House>.*?)City:(?<City>.*?)Postal Code:(?<PostalCode>.*?)

You can then get each group's value out of the match object's .groups property.

I am going to suggest the following alternative which makes a JSON string of your input then parses that in to a native JavaScript object. Then you can use the properties as you wish.

var funstring = "Street name: Main St\r\nHouse number: 3250\r\nCity: Corona\r\nState: CA\r\nPostal code: 92882\r\nCountry: United States";
//make valid JSON string of it and parse that
let x2 = JSON.parse('{ "' + funstring.replace(/\r\n/g, '","').replace(/\:\s+/g, '":"') + '" }');
//now x2 is a JavaScript object and you can get any property you want from it
//let's do so consumption of the objects properties just for examples:
console.log(x2, x2["House number"]);
const props = Object.getOwnPropertyNames(x2);
// all the names:
console.log(props);

let addressString = x2["House number"] + " " + x2["Street name"] + ", " + x2["City"] + " " + x2["State"] + " " + x2["Postal code"] + " " + x2["Country"];
console.log(addressString);
let addr = `${x2["House number"]} ${x2["Street name"]}, ${x2["City"]} ${x2["State"]} ${x2["Postal code"]}`;
console.log(addr);
let addrMultiLine = `${x2["House number"]} ${x2["Street name"]},
${x2["City"]} 
${x2["State"]} ${x2["Postal code"]}
${x2["Country"]}`;
console.log(addrMultiLine);

You can use a regex to capture all the fields you want in the input, and then use replace to generate a new string from the capture groups. I've used named capture groups in this example for clarity:

const regex = /Street name: (?<street>[^\r\n]+)\s+House number: (?<number>[^\r\n]+)\s+City: (?<city>[^\r\n]+)\s+State: (?<state>[^\r\n]+)\s+Postal code: (?<postcode>[^\r\n]+)\s+Country: (?<country>[^\r\n]+)/

const text = `Street name: Main St
House number: 3250
City: Corona
State: CA
Postal code: 92882
Country: United States`

const replacement = '$<number> $<street>, $<city> $<state> $<postcode>'

const result = text.replace(regex, replacement)

console.log(result)

Related