現在、正規表現にマッチしてる文字をリータンするロジックを作ってます。
コードは以下のとおりです。
function regexTest(str){ const regex = RegExp('^([0-6]?[0-9]):([0-6]?[0-9])'); if (regex.test(str)) { console.log('match') return str } else { console.log('unmatch') return undefined } }
上記コードに機能追加で
条件を複数マッチした場合、マッチした文字から新しくマッチした文字以前までを取り出して
マッチした分配列に入れてreturnしたいです。
期待値は以下のように考えてます
// pattern1 regexTest('0:18 hoge') // -> except return '0:18 hoge' // pattern2 regexTest('hoge 0:34 hoge') // -> except return 'hoge 0:34 hoge' // pattern3 regexTest('0:18 hoge 0:34 hoge') // -> except return ['0:18 hoge', '0:34 hoge']
pattern1,pattern2はできてますが、pattern3を具現するにはどうすればよいかがわからずこちらに質問させていただきました。
ヒントになるキーワードでもよいので実装方法をご教示いただけますか?
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/11/03 23:59
回答6件
3
いくつか気になる点はありますが、
- 返り値の種類によって条件分岐処理が必要(複雑化する)
- 「分:秒」の書式に見えて、
69:69
を許容する(そもそも、「分:秒」なら1:60
は2:00
ですが)
String#match
を利用すれば、実装できます。
JavaScript
1const sample = string => { 2 const result = string.match(/^(?:(?![0-6]?\d:[0-6]?\d)[\s\S])+|[0-6]?\d:[0-6]?\d(?:(?![0-6]?\d:[0-6]?\d)[\s\S])*/g); 3 return result && result.length > 1 ? result : string; 4}; 5 6console.log(sample('0:18 hoge')); // "0:18 hoge" 7console.log(sample('foo 69:69 bar')); // ["foo ", "69:69 bar"] 8console.log(sample('0:18 hoge 0:34 hoge')); // ["0:18 hoge ", "0:34 hoge"]
String#match
の返り値をそのまま使用すれば、条件分岐処理が不要になり、汎用性が高くなります。
Re: Kimsehwa さん
投稿2019/11/01 11:56
総合スコア18189
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
3
思ったより汚くなっちまった。
javascript
1alert(regexTest("0:18 hoge")); 2alert(regexTest('hoge 0:34 hoge')) 3alert(regexTest('0:18 hoge 0:34 hoge')) 4 5function regexTest(str) { 6 // 正規表現定義して 7 const regex = RegExp("([0-6]?[0-9]:[0-6]?[0-9])"); 8 // "XX:XX"を区切り文字として分割して 9 const arr = str.split(regex); 10 // それを結合して配列にいれる 11 const result = []; 12 let tmp = "" 13 for (let i = 0, l = arr.length, beforeMatch = true; i < l; i++) { 14 if (regex.test(arr[i])) { 15 if (!beforeMatch) { 16 if (tmp) result.push(tmp.trim()); 17 tmp = ""; 18 } 19 beforeMatch = false; 20 } 21 tmp += arr[i]; 22 } 23 if (tmp) result.push(tmp); 24 return result.length === 1 ? result[0] : result; 25}
投稿2019/11/01 06:17
編集2019/11/01 06:19退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
3
ベストアンサー
仕様がよくわからないのでとりあえず動くもの
javascript
1function regexTest(str){ 2 const r1 = RegExp('^(?:([0-5]?[0-9]:[0-5]?[0-9]) .*? ?)+$'); 3 const r2 = RegExp('[0-5]?[0-9]:[0-5]?[0-9] .*?( |$)','g'); 4 if(r1.test(str)){ 5 const r3=str.match(r2); 6 console.log('match') 7 return r3; 8 } else { 9 console.log('unmatch') 10 return undefined 11 } 12} 13console.log(regexTest('0:18 hoge')); 14console.log(regexTest('hoge 0:34 hoge')); 15console.log(regexTest('0:18 hoge 0:34 hoge')); 16console.log(regexTest('0:18 hoge 0:34 hoge 0:41 hoge 0:55 hoge')); 17
調整版
あ、2番めはマッチするですね、であればこうです
javascript
1function regexTest(str){ 2 const pattern=".*?[0-5]?[0-9]:[0-5]?[0-9] ?.*?"; 3 const r1 = RegExp('^(?:'+pattern+' ?)+$'); 4 const r2 = RegExp(pattern+'( |$)','g'); 5 if(r1.test(str)){ 6 const r3=str.match(r2); 7 console.log('match') 8 return r3; 9 } else { 10 console.log('unmatch') 11 return undefined 12 } 13} 14console.log(regexTest('hoge hoge')); 15console.log(regexTest('0:18 hoge')); 16console.log(regexTest('hoge 0:34 hoge')); 17console.log(regexTest('0:18 hoge 0:34 hoge')); 18console.log(regexTest('0:18 hoge 0:34 hoge 0:41 hoge 0:55 hoge'));
投稿2019/11/01 03:55
編集2019/11/01 10:20総合スコア116694
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2
こんにちは
ご質問のタイトルが、「正規表現に複数マッチした場合、文字列をsplitしてreturnしたい」ということだったので、split
を使うコードを回答します。
また、この回答では、入力される文字列を
- 文字列
"hoge"
と、"hoge"
ではなくかつ空白を含まない文字列(例:"0:18"
)とが、スペース区切りで交互に出現し、 - 最後は
"hoge"
で終わり、 - 先頭に空白文字は無い。
というものとして捉えました。以下、期待値を得るコードになります。
javascript
1const FIXEDSTR = 'hoge'; 2 3function regexTest(str){ 4 5 let ary = str.split(/\s+/); 6 7 if (ary.length > 1) { 8 if (ary[0] === FIXEDSTR) { 9 ary.shift(); 10 ary[0] = `${FIXEDSTR} ${ary[0]}`; 11 } 12 ary = ary.map((s, i) => i%2 ? null : `${s} ${FIXEDSTR}`).filter(s => s); 13 } 14 15 return ary.length === 1 ? ary[0] : ary; 16} 17 18// pattern1 19console.log(regexTest('0:18 hoge')); // => "0:18 hoge" 20 21// pattern2 22console.log(regexTest('hoge 0:34 hoge')); // => "hoge 0:34 hoge" 23 24// pattern3 25console.log(regexTest('0:18 hoge 0:34 hoge')); // => "[ '0:18 hoge', '0:34 hoge' ]" 26
- 動作確認用jsFiddle: https://jsfiddle.net/jun68ykt/bkmLxctd/4/
上記では、"hoge"
ではなくかつ空白を含まない文字列が満たすべき正規表現^([0-6]?[0-9]):([0-6]?[0-9])
は使用していませんが、pattern1からpattern3 の入力に対しては、望まれる結果が出力されます。
とはいえ、 ご質問にある ^([0-6]?[0-9]):([0-6]?[0-9])
を使わない上記のコードでは、望む結果が得られないような、別の(pattern4 以降の)入力パターンとそれに対する期待値が、おそらくあると思われましたので、それらについては、コメントからお知らせ頂くか、質問に追記をお願い致します。
追記
([0-6]?[0-9]):([0-6]?[0-9])
に合致しない文字列、たとえば "70:70"
といったものも、解析対象の文字列に入ってくる可能性があり、それを排除する必要があったりするならば、([0-6]?[0-9]):([0-6]?[0-9])
にも出番はあると思いますが、ご質問にある pattern1 〜 pattern3 の事例では、hoge以外の全てのトークンは [0-6]?[0-9]:[0-6]?[0-9]
を満たしていることが目視で確認できますので、([0-6]?[0-9]):([0-6]?[0-9])
は不要になります。このように、正規表現の課題を考える場合、解析対象の文字列ではそもそも何が満たされていることを前提にしてよいのかをはっきりさせることで、正規表現を使ったプログラム側を(当初、想定していたものよりも)簡素にできることがあります。
以上、参考になれば幸いです。
投稿2019/11/01 14:37
編集2019/11/02 06:23総合スコア9058
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2
regex.test() はマッチしたかどうかの結果を返します。
regex.exec() はパターンにどのようにマッチしたかの配列を返します。
matched のように適当な変数に代入すると、パターンとの関係がつかみやすくなります。
javascript
1 // regexp, strは略 2 let matched; 3 if (matched = regex.exec(str)) { 4 console.log( "matched :", matched);// 配列 5 }
正規表現のパターンについては、今一度、ご自身で調べてみてください。
ヒント:
RegExp オブジェクトの引数
- パターン:時刻部分しか定義できていません。(正規表現をググる)
- フラグ:3つめの期待値を得るためには?
追記)
正規表現 match() と exec() の違いにあるように、全体を一気に取得できる match() を使いました。
javascript
1function regexTest(str){ 2 var regex = RegExp("\s?([0-6]?[0-9]\:[0-6]?[0-9])?\s?([\w]+)","g") 3 , m 4 ; 5//if ( m = regex.exec(str) ) { 6 if ( m = str.match(regex) ) { // matchを使う 7 //console.log( "matched:", m ); 8 9 // マッチ結果 m には配列が来るので、期待値に合わせて調整 10 if( m.length === 1 ) { 11 str = m[0]; 12 } 13 else if( m[0].match(/^[^\d]/) ) { 14 str = m.join("") 15 } 16 else { 17 str = m 18 } 19 return str 20 } else { 21 console.log('unmatch') 22 return undefined 23 } 24} 25var list = ['0:18 hoge','hoge 0:34 hoge','0:18 hoge 0:34 hoge']; 26list.forEach( (src, idx) => { 27 console.log( `#${idx} result :`, regexTest( src ) ) 28});
正規表現のマッチパターンの作り方:
次のようにチェックしながらどの文字を使うべきか検討してゆきます。
正規表現リテラル: RegExp()と違い、バックスラッシュ(\)を二重に書かずに済みます /\s?([0-6]?[0-9]\:[0-6]?[0-9])?\s?([\w]+)/g "g"は繰り返し =========================== ======= 0:18 hoge ---> '0:18 hoge' ---------------------------------------- hoge -+-> 'hoge 0:34 hoge' 0:34 hoge -+ ---------------------------------------- 0:18 hoge -+-> '0:18 hoge 0:34 hoge' 0:34 hoge -+
投稿2019/11/01 03:53
編集2019/11/01 08:38総合スコア5434
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
発想はjjj_aaaさんのと似ています。つまり、
- 00:00な文字列で対象を分割(ただし00:00自身もメンバーに含める)。
- 分割リストの1番目と2番目、3番目と4番目…を結合してこれを結果とする。
- ただし分割リストの0番目は結果リストの最初に連結する。
配列と単純文字列を出力し分ける必然性を感じなかったので、その処理は省略しています。どうしても必要ならlengthをみて変換とかすればいいと思いますが。
function regexTest(str){ const regex = RegExp("(\d{1,2}:\d{1,2})"); const arr = str.split(regex); r = []; for(i=1; i<=arr.length-2; i+=2){ r.push(arr[i]+arr[i+1]); } r[0] = arr[0]+r[0]; return(r); } console.log(regexTest("0:18 hoge")); console.log(regexTest('hoge 0:34 hoge')); console.log(regexTest('0:18 hoge 0:34 hoge'));
投稿2019/11/03 11:22
総合スコア13692
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。