JavaScript で複数の区切り文字を使用して文字列を分割するにはどうすればよいですか?
コンマとスペースの両方で分割しようとしていますが、AFAIK JavaScript のsplit()関数は 1 つのセパレーターしかサポートしていません。
JavaScript で複数の区切り文字を使用して文字列を分割するにはどうすればよいですか?
コンマとスペースの両方で分割しようとしていますが、AFAIK JavaScript のsplit()関数は 1 つのセパレーターしかサポートしていません。
パラメータとして正規表現を渡します。
js> "Hello awesome, world!".split(/[\s,]+/)
Hello,awesome,world!
追加するために編集:
配列の長さから 1 を引いたものを選択すると、最後の要素を取得できます。
>>> bits = "Hello awesome, world!".split(/[\s,]+/)
["Hello", "awesome", "world!"]
>>> bit = bits[bits.length - 1]
"world!"
...そして、パターンが一致しない場合:
>>> bits = "Hello awesome, world!".split(/foo/)
["Hello awesome, world!"]
>>> bits[bits.length - 1]
"Hello awesome, world!"
JavaScript のsplit()メソッドに正規表現を渡すことができます。例えば:
"1,2 3".split(/,| /)
["1", "2", "3"]
または、複数のセパレーターをまとめて 1 つのみとして機能させたい場合は、次のようにします。
"1, 2, , 3".split(/(?:,| )+/)
["1", "2", "3"]
(非キャプチャ(?:)括弧を使用する必要があります。そうしないと、結果にスプライスされてしまうからです。または、Aaron のように賢く、文字クラスを使用することもできます。)
Safari と Firefox でテストされた例。
別の単純だが効果的な方法は、分割と結合を繰り返し使用することです。
"a=b,c:d".split('=').join(',').split(':').join(',').split(',')
基本的に、分割の後に結合を行うことは、グローバル置換に似ているため、各セパレーターをコンマに置き換え、すべてが置換されると、コンマで最終的な分割を行います
上記の式の結果は次のとおりです。
['a', 'b', 'c', 'd']
これを拡張すると、関数に配置することもできます。
function splitMulti(str, tokens){
var tempChar = tokens[0]; // We can use the first token as a temporary join character
for(var i = 1; i < tokens.length; i++){
str = str.split(tokens[i]).join(tempChar);
}
str = str.split(tempChar);
return str;
}
使用法:
splitMulti('a=b,c:d', ['=', ',', ':']) // ["a", "b", "c", "d"]
この機能を頻繁に使用する場合は String.prototype.split、利便性のためにラッピングを検討する価値さえあるかもしれません (私の関数はかなり安全だと思います - 唯一の考慮事項は、条件の追加のオーバーヘッド (マイナー) と、制限引数の実装がないという事実です)配列が渡された場合)。
splitMulti以下にこのアプローチを使用して単純にラップする場合は、必ず関数を含めてください:)。また、ビルトインの拡張に眉をひそめる人がいることにも注意してください (多くの人が間違っており、競合が発生する可能性があるため)。疑いがある場合は、これを使用する前に上級者に相談するか、SO で質問してください:)
var splitOrig = String.prototype.split; // Maintain a reference to inbuilt fn
String.prototype.split = function (){
if(arguments[0].length > 0){
if(Object.prototype.toString.call(arguments[0]) == "[object Array]" ) { // Check if our separator is an array
return splitMulti(this, arguments[0]); // Call splitMulti
}
}
return splitOrig.apply(this, arguments); // Call original split maintaining context
};
使用法:
var a = "a=b,c:d";
a.split(['=', ',', ':']); // ["a", "b", "c", "d"]
// Test to check that the built-in split still works (although our wrapper wouldn't work if it didn't as it depends on it :P)
a.split('='); // ["a", "b,c:d"]
楽しみ!
簡単にしましょう: (RegEx に "[ ]+" を追加すると、"1 つ以上" を意味します)
これは、"+" と "{1,}" が同じであることを意味します。
var words = text.split(/[ .:;?!~,`"&|()<>{}\[\]\r\n/\\]+/); // note ' and - are kept
分割関数をさらにカスタマイズしたい方のために、分割する文字のリストを使用して特定の文字列を分割する再帰アルゴリズムを作成しました。上記の投稿を見る前にこれを書きました。欲求不満のプログラマーの助けになることを願っています。
splitString = function(string, splitters) {
var list = [string];
for(var i=0, len=splitters.length; i<len; i++) {
traverseList(list, splitters[i], 0);
}
return flatten(list);
}
traverseList = function(list, splitter, index) {
if(list[index]) {
if((list.constructor !== String) && (list[index].constructor === String))
(list[index] != list[index].split(splitter)) ? list[index] = list[index].split(splitter) : null;
(list[index].constructor === Array) ? traverseList(list[index], splitter, 0) : null;
(list.constructor === Array) ? traverseList(list, splitter, index+1) : null;
}
}
flatten = function(arr) {
return arr.reduce(function(acc, val) {
return acc.concat(val.constructor === Array ? flatten(val) : val);
},[]);
}
var stringToSplit = "people and_other/things";
var splitList = [" ", "_", "/"];
splitString(stringToSplit, splitList);
上記の例は次を返します。["people", "and", "other", "things"]
注:flatten関数はRosettaコードから取得されました
セパレーターとして使用するすべての文字を単独またはまとめて正規表現にまとめて、分割関数に渡すことができます。たとえば、次のように書くことができます。
console.log( "dasdnk asd, (naks) :d skldma".split(/[ \(,\)]+/) );
出力は次のようになります。
["dasdnk", "asd", "naks", ":d", "skldma"]
そのような関数の古典的な実装を提供します。このコードは、JavaScript のほぼすべてのバージョンで機能し、何らかの形で最適化されています。
純粋なコード:
var text = "Create a function, that will return an array (of string), with the words inside the text";
println(getWords(text));
function getWords(text)
{
let startWord = -1;
let ar = [];
for(let i = 0; i <= text.length; i++)
{
let c = i < text.length ? text[i] : " ";
if (!isSeparator(c) && startWord < 0)
{
startWord = i;
}
if (isSeparator(c) && startWord >= 0)
{
let word = text.substring(startWord, i);
ar.push(word);
startWord = -1;
}
}
return ar;
}
function isSeparator(c)
{
var separators = [" ", "\t", "\n", "\r", ",", ";", ".", "!", "?", "(", ")"];
return separators.includes(c);
}
プレイグラウンドで実行されているコードを確認できます: https://codeguppy.com/code.html?IJI0E4OGnkyTZnoszAzf
これが必要な主な理由の 1 つは、 と の両方/でファイル パスを分割することです\。ちょっとトリッキーな正規表現なので、参考のためにここに投稿します。
var splitFilePath = filePath.split(/[\/\\]/);
RegEx のパフォーマンスはわかりませんが、代わりに RegEx がネイティブの HashSet を活用し、O( max(str.length, delimeter.length) ) の複雑さで動作する別の方法を次に示します。
var multiSplit = function(str,delimiter){
if (!(delimiter instanceof Array))
return str.split(delimiter);
if (!delimiter || delimiter.length == 0)
return [str];
var hashSet = new Set(delimiter);
if (hashSet.has(""))
return str.split("");
var lastIndex = 0;
var result = [];
for(var i = 0;i<str.length;i++){
if (hashSet.has(str[i])){
result.push(str.substring(lastIndex,i));
lastIndex = i+1;
}
}
result.push(str.substring(lastIndex));
return result;
}
multiSplit('1,2,3.4.5.6 7 8 9',[',','.',' ']);
// Output: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
multiSplit('1,2,3.4.5.6 7 8 9',' ');
// Output: ["1,2,3.4.5.6", "7", "8", "9"]
削除したいものではなく、残したいものを指定した方が簡単だと思います。
英単語だけを使いたい場合は、次のようなものを使用できます。
text.match(/[a-z'\-]+/gi);
例 (実行スニペット):
var R=[/[a-z'\-]+/gi,/[a-z'\-\s]+/gi];
var s=document.getElementById('s');
for(var i=0;i<R.length;i++)
{
var o=document.createElement('option');
o.innerText=R[i]+'';
o.value=i;
s.appendChild(o);
}
var t=document.getElementById('t');
var r=document.getElementById('r');
s.onchange=function()
{
r.innerHTML='';
var x=s.value;
if((x>=0)&&(x<R.length))
x=t.value.match(R[x]);
for(i=0;i<x.length;i++)
{
var li=document.createElement('li');
li.innerText=x[i];
r.appendChild(li);
}
}
<textarea id="t" style="width:70%;height:12em">even, test; spider-man
But saying o'er what I have said before:
My child is yet a stranger in the world;
She hath not seen the change of fourteen years,
Let two more summers wither in their pride,
Ere we may think her ripe to be a bride.
—Shakespeare, William. The Tragedy of Romeo and Juliet</textarea>
<p><select id="s">
<option selected>Select a regular expression</option>
<!-- option value="1">/[a-z'\-]+/gi</option>
<option value="2">/[a-z'\-\s]+/gi</option -->
</select></p>
<ol id="r" style="display:block;width:auto;border:1px inner;overflow:scroll;height:8em;max-height:10em;"></ol>
</div>
引数の文字を使用して文字列を分割する C# string.Split() 関数の代わりを探しているときに、この質問に遭遇しました。
JavaScript では、 map と reduce を使用して同じことを行い、分割文字と中間値を反復処理できます。
let splitters = [",", ":", ";"]; // or ",:;".split("");
let start= "a,b;c:d";
let values = splitters.reduce((old, c) => old.map(v => v.split(c)).flat(), [start]);
// values is ["a", "b", "c", "d"]
flat() は中間結果を平坦化するために使用されるため、各反復はネストされた配列のない文字列のリストで機能します。各反復は、old のすべての値に分割を適用し、スプリッターの次の値で分割される中間結果のリストを返します。reduce() は、初期文字列値を含む配列で初期化されます。
これをreduceとfilterで解決しました。それは最も読みやすい解決策や最速の解決策ではない可能性があり、実際にはおそらくAarons answere hereを使用するでしょうが、書くのは楽しかったです。
[' ','_','-','.',',',':','@'].reduce(
(segs, sep) => segs.reduce(
(out, seg) => out.concat(seg.split(sep)), []),
['E-mail Address: user@domain.com, Phone Number: +1-800-555-0011']
).filter(x => x)
または関数として:
function msplit(str, seps) {
return seps.reduce((segs, sep) => segs.reduce(
(out, seg) => out.concat(seg.split(sep)), []
), [str]).filter(x => x);
}
これは出力されます:
['E','mail','Address','user','domain','com','0','Phone','Number','+1','800','555','0011']
最後にフィルターがないと、2 つの異なるセパレーターが隣り合っている配列に空の文字列が表示されます。