-2

I want to get all categories listed in example below fruit and meat but not word mandatory but I want to still get mandatory if present :

categories fruit meat mandatory

I tried to inspire from Match everything except for specified strings

https://regex101.com/r/peXJXx/1

/(categories )(^(?!.+(mandatory)))(mandatory)?/gis

But can't get it work

user310291
  • 36,946
  • 82
  • 271
  • 487
  • 1
    Maybe you want something like `\b(?:(?!mandatory\b)(?\w+)|(?mandatory))\b`? See [this demo](https://regex101.com/r/7l46hq/1). – Wiktor Stribiżew May 30 '22 at 07:35
  • Please add more detail to the question. Does the string only contain this categories stuff or is it part of a larger string and should get extracted? Is "mandatory" always the last word? Do you need the categories broke into words or just the substring? Should "categories" also be captured into a group? ... – bobble bubble May 30 '22 at 07:58
  • 2
    Try something like this `/(?categories)|(?mandatory)|(?\w*)/gm` https://regex101.com/r/bnt7np/1 – Zei May 30 '22 at 08:09
  • @Zei Good idea, thought of same - however better to use `\w+` instead `\w*` – bobble bubble May 30 '22 at 08:12
  • @bobblebubble Yeah spot on. That removes null values when the empty spaces are matched. – Zei May 30 '22 at 08:14
  • @bobblebubble yeah I deleted it. I can't get JS `exec()` function to work properly with the named capture groups. I have no idea why. Just doesn't seem to be working properly. – Zei May 30 '22 at 08:23
  • @Zei Well, the JS stuff is a different thing, not directly asked... nowadays they use [`matchAll`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll) which makes life easier... why not just use normal capture group. – bobble bubble May 30 '22 at 08:25
  • What is the exact expected output for the `categories fruit meat mandatory` string? – Wiktor Stribiżew May 30 '22 at 08:39
  • @bobblebubble good call, I went ahead and redid my answer with matchAll. Removed the named capture groups as they seem to be a bit weird. – Zei May 30 '22 at 08:41

2 Answers2

0
const r = 'categories fruit meat mandatory';
const [, ...categories] = r.split(' ').filter(_ => _ !== 'mandatory');

You don't need Regex for such a problem, I used split(' ') to split the string into words (convert it to an array), then filter them from 'mandatory', I used also destructuring to remove the first element.

0

If you insist on using regex, this might be what you want.

const input = "categories fruit meat mandatory";
const regex = /\w+/gm;
const regex2 = /^\w+/g;

const results = input.matchAll(regex);

let type = input.match(regex2)[0];

let isMandatory = false;
let isCategory = false;
let categories = [];
for (const result of results){
    switch(result[0]){
    case "categories": isCategory = true; break;
    case "mandatory": isMandatory = true; break;
    default: categories.push(result[0]);
  }
}
console.log("Type: " + type);
console.log("Categories: " + categories.join(", "));
console.log("Mandatory: " + (isMandatory ? "Yes" : "No"));
Type: categories
Categories: fruit, meat
Mandatory: Yes

You can spruce it up however you want. Essentially if you have multiple inputs, you'd loop over each string and run this code. If you have other types instead of category, you can add something like isDepartment = false and then in the switch do case "departments": isDepartment = true; break;.

You could also just modify the regex to ignore the first word and create a second regex pattern to identify what the first word is specifically like const regex2 = /^\w+/g; and then do let type = input.match(regex2)[0];.

Here's a live sample https://jsfiddle.net/gey3oqLp/1/

Edit: Actually now that I think about it. If we're going the switch route, we don't need to match anything specific in the regex. We only need to match each word and deal with it later down the road. I've removed updated the regex to the simpler version.

Zei
  • 409
  • 5
  • 14
  • 1
    @WiktorStribiżew yep you're right. I removed the unnecessary capture groups left over from when I had the named capture groups. – Zei May 30 '22 at 08:43
  • 1
    @bobblebubble apparently not needed. MatchAll already returns each match as its own value in the array and then the switch statement does the real work. So no capture groups necessary in the actual regex. See my JSFiddle. – Zei May 30 '22 at 08:48
  • 1
    @bobblebubble I was already onto it! This is a Javascript problem, not a regex problem. It should be solved with Javascript as we've done in the answer. We just need to identify each word. Really the only difference between this and @KhobiziIlyes answer is that we're identifying words specifically and any boundary can be used. That means that `categories|fruit.meat&mandatory` would still be a valid matchable string. – Zei May 30 '22 at 08:54
  • 1
    Thank you for taking the time, yea... [This is what I was initially thinking of](https://tio.run/##XY/NCsIwEITveYr1lqBW0ItQevLsE6hgiNs2kjYlSf1Bffa6TfH3EsLMNzu7R3mSXjndhOlp2XXMYACHBV4ggxlXMmBhnUYv7ryS9UEG6670357HYlZUaeR9cETvPzDkrtUBKpT0vFL7AdZ@5YnOpfGYwqCsfwUa1CObXcrYudQGgVN5UCWJcbcEL6g41QoBoyyDujVGsBsD0PlAbha7URZl6GWIM5Om9eXbFykZD0Cq/cTmf7Fht@Ba/KJfVjzk7bEHY8rW3hpMjC04RSc9M@mrqazrng). Actually I was confused by the `matchall` (tried it first time) somehow addressing the capturing groups seemed confusing to me :p But I'm here to learn and I'm absolutely not from Javascript myself. – bobble bubble May 30 '22 at 09:31
  • @Zei yes I do "INSIST" on using regex ;) – user310291 May 30 '22 at 18:32
  • @user310291 yeah I figured, I was just a bit self-conscious with the other guy answering without it. Hope this helped. – Zei May 30 '22 at 21:42