こうこく
作 ▸

JavaScript 文字列をスペースでsplit、ただしダブルクォートの内側は残す

正規表現わかんないから普通にやった 。 ゚(゚^ω^゚)゚。

/**
 * 文字列を半角スペースで区切る。ダブルクォートの内側は区切らない (エスケープされていれば区切る)。
 * @param  {String} str 文字列
 * @return {Array} 区切られた文字列の配列
 */
function splitNicely(str) {
	if (str !== String(str)) {
		return [str];
	}
	const arr = [];
	let buff = '';
	let escaped = false;
	let quoted = false;
	for (let i = 0, len = str.length; i < len; ++i) {
		const c = str.charAt(i);
		if (c === '\\') {
			escaped = true;
		} else {
			if (!escaped && c === '"') {
				const prev = str.charAt(i - 1);
				const next = str.charAt(i + 1);
				if (!quoted && (prev === '' || prev === ' ')) {
					quoted = true;
				} else if (quoted && (next === '' || next === ' ')) {
					quoted = false;
				} else {
					buff += c;
				}
			} else if (!quoted && c === ' ') {
				arr.push(buff);
				buff = '';
			} else {
				buff += c;
			}
			escaped = false;
		}
	}
	arr.push(buff);
	return arr;
}

// こんな感じ
console.log( splitNicely(`aaa "bbb" ccc`) );    // -> ["aaa", "bbb", "ccc"]
console.log( splitNicely(`a"aa b"bb c"c"c`) );  // -> ["a"aa", "b"bb", "c"c"c"]

通ったテスト

function assert(actArr, expArr) {
	console.log('act=', actArr, 'exp=', expArr);
	const len = actArr.length;
	if (len !== expArr.length) {
		throw new Error(actArr.length +' !== '+ expArr.length);  // 要素数違ったらNG
	}
	for (let i = 0; i < len; ++i) {
		if (actArr[i] !== expArr[i]) {
			throw new Error(actArr[i] +' !== '+ expArr[i]);  // 中身違ったらNG
		}
	}
}

assert( splitNicely(), [undefined] );
assert( splitNicely(null), [null] );
assert( splitNicely(``), [''] );
assert( splitNicely(`aaa`), ['aaa']);
assert( splitNicely(`aaa bbb ccc`), ['aaa', 'bbb', 'ccc'] );
assert( splitNicely(`aaa "bbb" ccc`), ['aaa', 'bbb', 'ccc'] );
assert( splitNicely(`a"aa b"bb c"c"c`), ['a"aa', 'b"bb', 'c"c"c'] );
assert( splitNicely(`"" aaa bbb ccc`), ['', 'aaa', 'bbb', 'ccc'] );
assert( splitNicely(`"aaa bbb" ccc`), ['aaa bbb', 'ccc'] );
assert( splitNicely(`aaa "bbb ccc"`), ['aaa', 'bbb ccc'] );
assert( splitNicely(`aaa "bbb ccc" ddd`), ['aaa', 'bbb ccc', 'ddd'] );
assert( splitNicely(`"\\"aaa bbb" ccc`), ['"aaa bbb', 'ccc'] );
assert( splitNicely(`"aaa bbb\\"" ccc`), ['aaa bbb"', 'ccc'] );
assert( splitNicely(`"aa\\"a b\\"bb" ccc`), ['aa"a b"bb', 'ccc'] );
assert( splitNicely(`"" "aa\\"a b\\"bb" ccc`), ['', 'aa"a b"bb', 'ccc'] );
assert( splitNicely(`GET 200 "http://aaa/bbb.html" "123 \\"456\\" 789" xxxxxx`), ['GET', '200', 'http://aaa/bbb.html', '123 "456" 789', 'xxxxxx'] );
この記事に何かあればこちらまで (非公開)