JavaScript の質問です。
次の文字列のデータ captions
があるとします。
時刻と文字が繰り返し現れるデータです。
let cartions = "3 - My nail, 6 is very big. 11 (lively music) 26 - Konnichiwa everyone? 27 - Konnichiwa. 29 - Oh Japan. 32 - I wanna scream. 33 May I? 35 (screams) 43 - Oh that's Japanese. 45 I know it. 49 - Oh. 50 - Oh it smells good. 53 (mumbles) 56 - Yum. 58 (mumbles) 65 - Spicy. 70 - I wonder why they make it"
この captions
を、JavaScript で以下の多次元配列に変換しるには、どうすればいいでしょうか?
[["3", "- My nail,"], ["6", "is very big."], ["11", "(lively music)"], ["26", "- Konnichiwa everyone?"], ["27","Oh Japan."], ["29","- I wanna scream."], ["32","May I?"], ["35","(screams)"], ["43","- Oh that's Japanese."], ["45","I know it."], ["49","- Spicy."], ["56","- Yum."], ["58","(mumbles)"], ["65","- Spicy."], ["70","- I wonder why they make it"], ]
ご助言、よろしくお願い致します。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/06/22 00:39
2020/06/22 03:02
回答7件
0
ベストアンサー
こんにちは。一例を挙げます。
javascript
1captions.split(/(?=\b\d)/).map(str => /^(\d+)\s+(.+[^\s]+)/.exec(str).slice(1));
- 動作確認用CodePen: https://codepen.io/jun68ykt/pen/abdJGyP?editors=0012
補足
上記のコードによって、ご質問にある captions
は、意図通りの二次元配列に分割されます。ただし検討事項として、ご質問にある
時刻と文字が繰り返し現れるデータ
の「文字」の部分に属すと思われる数字があっても、それも「時刻」とみて区切ってしまいます。たとえば、ご質問にある captions
には
11 (lively music)
が含まれていますが、これが以下
11 (lively 10 musics)
だったりすると、分割によって
javascript
1[ '11', '(lively 10 musics)' ]
になって欲しいものと思いますが、上記のコードだと、以下のような時刻と文字の組が二つあるものとして分割されます。
javascript
1[ '11', '(lively' ], [ '10', 'musics)' ]
投稿2020/06/22 02:45
総合スコア9058
0
String.prototype.split
の引数に正規表現オブジェクトを渡せばうまくいきそうです。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/split
の「RegExp で分割して結果に区切り文字列の一部を含める」のセクションをどうぞ。
JavaScript
1const content = "1 あ 22 い 333 う"; 2 3const words = content.split(/([0-9]+)/).slice(1); 4for (let i = 0; i < words.length; i += 2) { 5 console.log([words[i], words[i + 1]]); 6} 7 8/* 9[ '1', ' あ ' ] 10[ '22', ' い ' ] 11[ '333', ' う' ] 12*/
投稿2020/06/21 22:52
総合スコア2577
0
どこまでの処理が必要かわりませんがこんな感じ
投稿2020/06/22 00:43
編集2020/06/22 00:55総合スコア116724
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/06/22 00:54 編集
2020/06/22 00:56
2020/06/22 06:27
0
RegExp.prototype.exec
JavaScriptの正規表現系機能は、gフラグを付与すると、()
によるキャプチャが無効となる為、複数回のマッチで対応します。
- RegExp#exec + 繰り返し構文
- String#replace + コールバック関数
今回、String#replaceの返り値を必要としない為、前者で実装します。
JavaScript
1let string = "3 - My nail, 6 is very big. 11 (lively music) 26 - Konnichiwa everyone? 27 - Konnichiwa. 29 - Oh Japan. 32 - I wanna scream. 33 May I? 35 (screams) 43 - Oh that's Japanese. 45 I know it. 49 - Oh. 50 - Oh it smells good. 53 (mumbles) 56 - Yum. 58 (mumbles) 65 - Spicy. 70 - I wonder why they make it"; 2 3const reg = /\s*(\d+) - ((?:(?!\d+ - )[\s\S])+)|([\s\S])/g, array = []; 4let result; 5 6while (result = reg.exec(string)) { 7 if (result[3]) throw new Error('parse error'); 8 array.push([result[1], result[2]]); 9}
gフラグ付のRegExp#execは同じ場所に複数回マッチする事はありませんが、読み飛ばしは発生するので、([\s\S])
で意図せぬ読み飛ばしにパースエラーを返すように正規表現を組みます。
※未検証コードの為、期待通りに動作しない可能性があります。
アルゴリズムは使えると思います。
Re: t-cool さん
投稿2020/06/22 03:54
編集2020/06/22 03:57総合スコア18189
0
時刻と文字が繰り返し現れるデータ
ご質問の修正を経てcaptions
は「秒単位の数値と文字が繰り返し現れるデータ」になっていますが、
初回の例では、正規表現で時刻フォーマット(hh:mm:dd)にマッチさせる方法が使えます。
javascript
1 2const firstData = "00:00:03 - My nail, 00:00:06 is very big. 00:00:11 (lively music) 00:00:26 - Konnichiwa everyone? 00:00:27 - Konnichiwa. 00:00:29 - Oh Japan. 00:00:32 - I wanna scream. 00:00:33 May I? 00:00:35 (screams) 00:00:43 - Oh that's Japanese. 00:00:45 I know it. 00:00:49 - Oh. 00:00:50 - Oh it smells good. 00:00:53 (mumbles) 00:00:56 - Yum. 00:00:58 (mumbles) 00:01:05 - Spicy. 00:01:10 - I wonder why they make it"; 3 4const parseCaptions = src => { 5 const int = n=>parseInt(n); 6 let rslt = [], segment, pointer = 0; 7 8 src.replace(/(\d{2}):(\d{2}):(\d{2})\s/g, (timeformat, hour, min, sec, offset)=>{ 9 10 if( !pointer ) segment=[]; 11 else { 12 segment.push( src.substring( pointer, offset ) ); 13 rslt.push( segment ); 14 segment = []; 15 pointer = offset; 16 } 17 segment.push( int(hour)*60*24 + int(min)*60 + int(sec) + "" ); 18 pointer += timeformat.length; 19 }); 20 21 segment.push( src.substring( pointer ) ); 22 rslt.push( segment ); 23 24 return rslt; 25} 26 27console.log( JSON.stringify(parseCaptions(firstData),null,2) );
ご助言、よろしくお願い致します
String#replace() の第二引数に関数を指定し、マッチしたタイミングの文字位置(offset
)を活用すると、whileループで行うような字句解析が実現できます。
要件「時刻と文字が繰り返し現れるデータ」の文字に、数字の混入を許容する場合は「特定のフォーマット(という特徴)+任意の文字」の組み合わせのほうが、字句解析としては処理しやすい事例かもしれません。
処理対象のデータが改行された複数行テキストであるなど、他にも特徴があれば、より変換しやすくなると思います。
投稿2020/06/22 03:30
編集2020/06/22 03:40総合スコア5434
0
draqさんの回答はすごいですね。
正規表現でsplitできるんだ。勉強になりました。
単純なものならよいのですが
正規表現は複雑になると、可読性が悪く、可変性が低く、デバッグもしくにいので
あまり使うべきではないと思っている派なので普通のコードで実現してみました。
js
1let cartions = "3 - My nail, 6 is very big. 11 (lively music) 26 - Konnichiwa everyone? 27 - Konnichiwa. 29 - Oh Japan. 32 - I wanna scream. 33 May I? 35 (screams) 43 - Oh that's Japanese. 45 I know it. 49 - Oh. 50 - Oh it smells good. 53 (mumbles) 56 - Yum. 58 (mumbles) 65 - Spicy. 70 - I wonder why they make it" 2 3const result = []; 4let buffer = ''; 5const cartionsArray = cartions.split(' '); 6cartionsArray.forEach(value => { 7 if (buffer !== '' && _.isInteger(Number(value))) { 8 const bufferArray = buffer.split(' '); 9 result.push([bufferArray[0], bufferArray.slice(1, bufferArray.length - 1).join(' ')]); 10 buffer = ''; 11 } 12 buffer += value + ' '; 13}); 14 const bufferArray = buffer.split(' '); 15 result.push([bufferArray[0], bufferArray.slice(1, bufferArray.length - 1).join(' ')]); 16 17console.log(result);
実行結果は次の通りです。
0: (2) ["3", "- My nail,"] 1: (2) ["6", "is very big."] 2: (2) ["11", "(lively music)"] 3: (2) ["26", "- Konnichiwa everyone?"] 4: (2) ["27", "- Konnichiwa."] 5: (2) ["29", "- Oh Japan."] 6: (2) ["32", "- I wanna scream."] 7: (2) ["33", "May I?"] 8: (2) ["35", "(screams)"] 9: (2) ["43", "- Oh that's Japanese."] 10: (2) ["45", "I know it."] 11: (2) ["49", "- Oh."] 12: (2) ["50", "- Oh it smells good."] 13: (2) ["53", "(mumbles)"] 14: (2) ["56", "- Yum."] 15: (2) ["58", "(mumbles)"] 16: (2) ["65", "- Spicy."] 17: (2) ["70", "- I wonder why they make it"] length: 18
投稿2020/06/28 05:47
編集2020/06/28 06:17総合スコア197
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
まずは、自分でコードを考えてくださいね
ヒントとしては文字列の規則性を考えてください。
それが解ったらその規則性をどのようにプログラムに当てはめていくか?
例えばindexOfなどを使ってみるとか
https://www.sejuku.net/blog/21049
indexOfを使ったアプローチが正解か?は解りませんがマズは色々試すことが重要です。
投稿2020/06/21 23:01
総合スコア765
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。