Разделите предложения на 'и' и удалите окружающие пробелы

84

У меня есть такой код:

var r = /(?:^\s*([^\s]*)\s*)(?:,\s*([^\s]*)\s*){0,}$/
var s = "   a   ,  b  , c "
var m = s.match(r)
m => ["   a   ,  b  , c ", "a", "c"]

Похоже, что вся строка была сопоставлена, но куда "b"делась? Я бы предпочел получить:

["   a   ,  b  , c ", "a", "b", "c"]

так что я могу сделать m.shift()с результатом, s.split(',')но также с удаленными пробелами.

Есть ли у меня ошибка в регулярном выражении или я неправильно понял String.prototype.match?

меандре
источник
Кстати, {0,}это то же самое, что и *.
pimvdb 08
ну sможет также быть ' a, c'или'a,b,c d e, f'
меандре 08
я
заменю

Ответы:

194

Вот довольно простой и понятный способ сделать это без сложных регулярных выражений.

var str = "   a   ,  b  , c "
var arr = str.split(",").map(function(item) {
  return item.trim();
});
//arr = ["a", "b", "c"]

Нативный .mapподдерживается в IE9 и выше: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map


Или в ES6 + он становится еще короче:

var arr = str.split(",").map(item => item.trim());

И для завершения, вот он в Typescript с информацией для ввода

var arr: string[] = str.split(",").map((item: string) => item.trim());
CBarr
источник
4
Чтобы быть разборчивым, вы можете избавиться от скобок вокруг аргумента карты: var arr = str.split(",").map(item=>item.trim());
Дэвид Джонс,
Я с @DavidJones по этому поводу. Если вы измените свой ответ, будет здорово. Мне очень помогли в моем случае, спасибо, ребята!
Уже сделано
Да, хороший момент - ответ обновлен, чтобы отразить это! Я лично всегда добавляю круглые скобки, поскольку я обычно пишу Typescript, и мне нравится предоставлять явную информацию о типе, чтобы вы всегда могли сразу узнать, что что-то такое.
CBarr
Это отличный ответ, Крис.
циклический
Просто и лучше !!
Рахул Сонванши
23

Вы можете попробовать это без сложных регулярных выражений.

var arr = "   a   ,  b  , c ".trim().split(/\s*,\s*/);
console.log(arr);

xfg
источник
17

Краткий ответ: используйте m = s.match(/[^ ,]/g);


Ваш RE не работает должным образом, потому что последняя группа соответствует самому последнему совпадению (= c). Если вы опустите {1,}$, будет возвращено совпадение " a , b ", "a", "b". Короче говоря, ваш RegExp возвращает столько совпадений, сколько указанные группы, если вы не используете globalфлаг/g . В этом случае возвращаемый список содержит ссылки на все совпавшие подстроки.

Для достижения эффекта используйте:

m = s.replace(/\s*(,|^|$)\s*/g, "$1");

Эта замена заменяет каждую запятую ( ,), начало ( ^) и конец ( $), окруженные пробелом, на исходный символ ( commaили ничего).

Если вы хотите получить массив, используйте:

m = s.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/);

Этот RE обрезает строку (удаляет все пробелы в начале и в конце, затем разбивает строку на <any whitespace>,<any whitespace>. Обратите внимание, что символы пробела также включают символы новой строки и табуляции. Если вы хотите придерживаться только пробелов, используйте пробел ( ) вместо \s.

Роб В
источник
@ Андрей Я расширил объяснение твоего RE. См. Мой второй пример для splitметода.
Rob W
я уже опубликовал его как комментарий к другому ответу. Интересно, могу ли я сделать это с одним регулярным выражением и одной операцией, или js regexp недостаточно умен?
меандре 08
@ Андрей Да, просто используйте s.match(/[^ ,]+/g). Как упоминалось в начале моего ответа, /gэто глобальный флаг, который возвращает все подходящие подстроки.
Роб У
@Andrew: Одна группа захвата создает одно совпадение, независимо от того, сколько квантификаторов вы добавляете. Если вы хотите , чтобы соответствовать a, bи c, вам нужны три пары скобок (не включая (?:...)):/(?:^\s*([^\s]*)\s*)(?:,\s*([^\s]*)\s*)(?:,\s*([^\s]*)\s*)$/
user123444555621
@RobW, s.match (/ [^,] + / g) работает именно так, как мне нужно, пожалуйста, добавьте его в свой ответ
меандре
17

Сокращение ES6:

str.split(',').map(item=>item.trim())
Дитер Грибниц
источник
9

Вы можете сделать это для своей цели
EDIT : удаление второй замены, как это предлагается в комментариях. s.replace(/^\s*|\s*$/g,'').split(/\s*,\s*/)
Сначала replaceобрезается строка, а затем splitфункция разбивается '\s*,\s*'. Это дает вывод ["a", "b", "c"]на входе " a , b , c "

Что касается того, почему ваше регулярное выражение не захватывает 'b', вы повторяете захваченную группу, поэтому захватывается только последнее вхождение. Подробнее об этом здесь http://www.regular-expressions.info/captureall.html.

Нарендра Ядала
источник
Я не хочу стирать все пробелы, только вокруг запятых или в начале / конце строки
Менандре 08
@ Андрей, разве это не все пробелы? или у вас есть предложения, которые вы хотите разделить?
Дэвид Хеллсинг
s.replace (/ ^ \ s * /, '') .replace (/ \ s * $ /, '') .split (/ \ s *, \ s * /) может это сделать
meandre
@Andrew Изменил ответ в соответствии с вашими требованиями.
Нарендра Ядала 08
7

Итак, наконец, я выбрал /(?=\S)[^,]+?(?=\s*(,|$))/g, что дает именно то, что мне нужно: все предложения, разделенные на ',' без окружающих пробелов.

'       a,    OMG     abc b a b, d o WTF        foo     '.
  match( /(?=\S)[^,]+?(?=\s*(,|$))/g )
=> ["a", "OMG     abc b a b", "d o WTF        foo"]

огромное спасибо!

меандре
источник
вот смысл, как я понимаю. пожалуйста, поправьте меня, если я не прав: (?=\S)- начинайте захват только тогда, когда впереди нет пробелов [^,]+- фиксируйте как можно больше «не запятых» ?- но не фиксируйте то, что может быть захвачено следующей группой (?=\s*(,|$))- фиксируйте все пробелы перед запятая или конец строки /g- повторить всю строку
meandre
2

Если вы хотите продолжать использовать регулярное выражение, сохраняйте код простым и без использования ES6:

s.replace(/ /g, '').split(",")

1 - Заменить все пробелы (/ / g) пустыми строками ('')

2 - Затем разделите его на массив

И вуаля

AlbertSY
источник
Это лучший и наименее сложный ответ.
Blazes