🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

Q&A

解決済

6回答

804閲覧

正規表現に複数マッチした場合、文字列をsplitしてreturnしたい

Kimsehwa

総合スコア312

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

正規表現

正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

0グッド

3クリップ

投稿2019/11/01 03:19

現在、正規表現にマッチしてる文字をリータンするロジックを作ってます。
コードは以下のとおりです。

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ページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yambejp

2019/11/01 03:36

1つだと文字列で、複数だと配列というのはあまりよくないですね
think49

2019/11/03 23:59

まだ解決できない状態(回答が意図したものではない)のであれば、意図が正しく伝わる文章/コードになるよう質問を修正して下さい。
guest

回答6

3

いくつか気になる点はありますが、

  • 返り値の種類によって条件分岐処理が必要(複雑化する)
  • 「分:秒」の書式に見えて、69:69 を許容する(そもそも、「分:秒」なら 1:602: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

think49

総合スコア18189

kei344, Kimsehwa👍を押しています

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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

kei344, Kimsehwa👍を押しています

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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
yambejp

総合スコア116694

kei344, Kimsehwa👍を押しています

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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

上記では、"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
jun68ykt

総合スコア9058

Kimsehwa👍を押しています

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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 オブジェクトの引数

  1. パターン:時刻部分しか定義できていません。(正規表現をググる)
  2. フラグ: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
AkitoshiManabe

総合スコア5434

Kimsehwa👍を押しています

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

発想はjjj_aaaさんのと似ています。つまり、

  1. 00:00な文字列で対象を分割(ただし00:00自身もメンバーに含める)。
  2. 分割リストの1番目と2番目、3番目と4番目…を結合してこれを結果とする。
  3. ただし分割リストの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

KojiDoi

総合スコア13692

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問