4

I have looked at this link and this link and few others but none of them seem to solve this with pure regex only (... not using replace, etc).

Input string: "Vehicle ServicesAUTOMATED GAS DISPENSER"

My desired output is: ["Vehicle Services", "AUTOMATED GAS DISPENSER"]

Here's my attempt:

var str = 'Vehicle ServicesAUTOMATED GAS DISPENSER'
console.log(str.split(/(?=[a-z][A-Z])/))

[ 'Vehicle Service', 'sAUTOMATED GAS DISPENSER' ]

I have a solution below but I don't like it because it uses an additional 'replace' method. I'm looking for a pure regex based split.

var str = 'Vehicle ServicesAUTOMATED GAS DISPENSER'
console.log(str.replace(/([a-z])(?=[A-Z])/, "$1_").split('_'))

[ 'Vehicle Services', 'AUTOMATED GAS DISPENSER' ]

Update: My requirement is simply to split the input string as specified in the post - as shown once the case flips to uppercase it remains in uppercase till the end.

Community
  • 1
  • 1
mpprdev
  • 1,273
  • 1
  • 15
  • 26
  • Have got it to work partially [JSFiddle](https://jsfiddle.net/r3344m3p/). – Rajesh Jul 10 '16 at 05:55
  • You example demonstrates that what you call "lowercase" can include capitals. You should explain exactly what constitutes lowercase. How many capitals can it have? can it only have them on the first letter? – Touffy Jul 10 '16 at 06:17
  • @Touffy - as stated in the title of the post, the split has to occur at the point where the case changes from lower to upper. – mpprdev Jul 10 '16 at 06:22
  • The "S" in "Services" is uppercase. So, technically, there should be a split between "Vehicle " and "Services" unless you explain what makes "Services" lowercase. I'd normally call it capitalized, but not lowercase. – Touffy Jul 10 '16 at 06:29
  • Fair enough. I'm still worried about the definition of the problem. What about "AUTOMATED GAS DISPENSERVehicle Services"? or is that not a case that can happen in the application? what about non-ASCII letters? – Touffy Jul 10 '16 at 06:49
  • I'm just dealing with facts. @rid – revo Jul 10 '16 at 07:13
  • OP, added an answer. If your requirements are more elaborate (such as needing the mixed case string to follow the all-uppercase string, or needing more than 1 pair, or needing non-ASCII characters, or anything else), then please specify that, because the answer in that case might be more elaborate as well (which might also make it harder to maintain and slower to run). – rid Jul 10 '16 at 07:16
  • @revo, is this better? :) – rid Jul 10 '16 at 07:16
  • @revo, you have to admit that covering all the situations possible will have a negative effect on performance and maintainability, which is to be avoided in case it's not absolutely required. After all, the best solutions are the simplest solutions that fully solve the problem and any possible edge cases within the bounds of the problem. – rid Jul 10 '16 at 07:17
  • Now to me it's acceptable and doesn't deserve a down-vote. @rid – revo Jul 10 '16 at 07:25
  • In such situtaions, we are not supposed to cover all possible cases but most, and I didn't ask you for the most but one. One that is more likely to happen. @rid – revo Jul 10 '16 at 07:26
  • @revo, or even better, just ask, as you pointed out. Looks like the OP doesn't need more pairs, which is great, since that keeps the solution simple. – rid Jul 10 '16 at 07:29

4 Answers4

1

This isn't perfect, but it's the best I could come up with for a single split without any identifier between the two.

var str = 'Vehicle ServicesAUTOMATED GAS DISPENSER';
var res = str.split(/([A-Z\s]+$)/);
console.log(res);

The only problem is that it leaves an extra array element with an empty string. You could pop it off or just ignore it if you're always expecting only two array elements.

JSFiddle https://jsfiddle.net/2ex4cuno/4/

As noted by @rid, you can add this to the split in order to get just the two results (again, assuming you are always only expecting 2 which I assume you would be).

var str = 'Vehicle ServicesAUTOMATED GAS DISPENSER';
var res = str.split(/([A-Z\s]+$)/, 2);
console.log(res);
Lawrence Johnson
  • 3,924
  • 2
  • 17
  • 30
1

If your use case is a mixed case string followed by an all-uppercase string, then an idea would be to use match instead of split, then read the results from the captured groups:

var str = 'Vehicle ServicesAUTOMATED GAS DISPENSER';
var result = str.match(/(.*[a-z])((?=[A-Z]).*)/);

console.log([result[1], result[2]]);
rid
  • 61,078
  • 31
  • 152
  • 193
0

Additional approach using RegExp.exec function:

var str = "Vehicle ServicesAUTOMATED GAS DISPENSER",
    parts = /([a-zA-Z ]+?)([A-Z ]+)$/.exec(str);

console.log(parts[1]);  // Vehicle Services
console.log(parts[2]);  // AUTOMATED GAS DISPENSER
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
0

JavaScript doesn't support lookbehinds, so if you're trying to split on the empty space between two characters, there's no way to validate the character before the empty space is a specific character. But capturing parentheses can also append elements to the resulting array from split. Thus you can create a solution like this:

var str = 'Vehicle ServicesAUTOMATED GAS DISPENSER'
var ar = str.split(/(.*[a-z])(?=[A-Z])/);
//result is ["", "Vehicle Services", "AUTOMATED GAS DISPENSER"]
ar.shift();//get rid of the leading empty element
console.log(ar);//["Vehicle Services", "AUTOMATED GAS DISPENSER"]

Another approach would be to have the empty match on the end of the resulting array rather than the beginning since split has a built-in parameter to limit the number of elements of the resulting array, thus we'd use AUTOMATED GAS DISPENSER as the delimiter, which you'd put between capturing parentheses, then we'd have the empty element on the end of the resulting array which we can simply strip off without calling pop:

var str = 'Vehicle ServicesAUTOMATED GAS DISPENSER'
var ar = str.split(/((?:[A-Z]{2,}\s*)+)/,2);
console.log(ar);//["Vehicle Services", "AUTOMATED GAS DISPENSER"]

But if you could come up with a piece of logic which can identify an empty space to split on using a lookahead alone, without having to look backwards, then you could write something like this:

var str = 'Vehicle ServicesAUTOMATED GAS DISPENSER'
var ar = str.split(/(?=AUTO)/);
console.log(ar);//["Vehicle Services", "AUTOMATED GAS DISPENSER"]
Ultimater
  • 4,647
  • 2
  • 29
  • 43