Вы можете использовать чередование с двумя частями, где год и сезон меняются местами, а затем захватывать только совпадающие захваты:
\b(?:(f(?:all)?|w(?:inter)?|s(?:pring|u(?:mmer)?)?)\s*(\d{2}(?:\d{2})?)|(\d{2}(?:\d{2})?)\s*(f(?:all)?|w(?:inter)?|s(?:pring|u(?:mmer)?)?))\b
См. Демонстрационную версию regex
Я заключил контракт с вашими альтернативами, чтобы сделать сопоставление более эффективным: все альтернативы должны совпадать только в уникальных местах.Кажется, что для вашего случая вполне достаточно границ слов.
В JS вы можете построить шаблон динамически:
var strs = ['Fall 2018','fall 18','2016 Fall','F2016','Fall2016'];
var season = "(f(?:all)?|w(?:inter)?|s(?:pring|u(?:mmer)?)?)";
var year = "(\\d{2}(?:\\d{2})?)";
var p = new RegExp("\\b(?:" + season + "\\s*" + year + "|" + year + "\\s*"+ season + ")\\b","i");
var results=[], m;
for (var s of strs) {
m = s.match(p);
if (m) {
if (m[1]) {
console.log(m[1],":", m[2]);
} else {
console.log(m[3],":", m[4]);
}
}
}