正規表現で商品名と商品画像、税込み価格、税抜き価格を抽出したい

\n�<02><08><0f><12><08>43533480<1a>C商品タイトルA"<00>*5https://hoge.com/sample1.jpg8�<01>I<00><00><00><00><00>`h@P<00>X\n`<03>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<02><00>�<02><00>�<02><00>�<02><00>�<02><00>�<02><07>�<02><00>�<02><00>�<02>�<01>�<02><01>�<02><00>�<02><00>�<03><00>�<03><00>�<03><01>�<03>Y\nIhttps://hoge.com/sample2.png<12><0c>商品タイトルB�<03><00>�<03><03>195�<04><03>178�<04><00>\n�<02><08><0f><12><08>42634028<1a>^商品タイトルC"<00>*Qhttps://hoge.com/sample3.jpg8lI<00><00><00><00><00>�]@P<00>X\n`<03>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<02><00>�<02><00>�<02><00>�<02><00>�<02><00>�<02><07>�<02><00>�<02><00>�<02>l�<02><01>�<02><00>�<02><00>�<03><00>�<03><00>�<03><01>�<03><00>�<03><03>118�<04><03>108�<04><00>\n�<02><08><0f><12><08>43531595<1a>J商品タイトルD"<00>*6https://hoge.com/sample4.jpeg8�<02>I<00><00><00><00><00><10>s@P<00>X\n`<03>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<01><00>�<02><00>�<02><00>�<02><00>�<02><00>�<02><00>�<02><07>�<02><00>�<02><00>�<02>�<02>�<02><01>�<02><00>�<02><00>�<03><00>�<03><00>�<03><01>�<03><00>�<03><03>305�<04><03>278�<04><00>
この文字列から正規表現で
- 商品ID
- 商品タイトル
- 商品画像
- 価格(税込・税抜)
を抽出したい。
結構いい線までいけているのだが、データに若干の揺れがありうまくいかない。
いい感じにメモできる場所が無いのでこのスクラップを使っていく。
なお、この文字列はFlutter on WebのCanvas Kitで作られたサイトで、gRPCのレスポンスデータに含まれる制御文字を16進数に置換したものである。16進数に置換すると01や04などの特徴的な文字列が出現した。

商品IDと商品タイトル
/<03>(?:<03>|<02>)(\d+)�<04>(?:<03>|<02>)(\d+)/g
これでいい感じに抽出できた。
商品画像
/https\:\/\/.+?(jpg|png|jpeg|gif|webp|avif|JPG|PNG|JPEG|GIF|WEBP|AVIF)/g
これで抽出できた。
と思いきや、バッヂがついてる商品もあり、
そのバッヂが _hatooshi-product.png<12><0c>ハトオシ
のようになっている。

税込み価格と税抜き価格
商品によっては価格の記載が無いようで、ルールの規則性があまり見えておらずまだ分からない。

問題解決のアプローチ
データ処理してみた結果うまくいったっぽいので、解決までのアプローチをメモしておく。
正規表現を分けた
const idRegex = /<12><08>(\d+)/;
const titleRegex = /<1a>(.+?)"/;
const priceRegex = /�<03>(<03>|<02>|<04>)(\d+)�<04>(<03>|<02>|<04>)(\d+)/;
const imageRegex = /(https:\/\/hoge\.imgix\.net\/[^sales_badges].+?\.(jpg|jpeg|png|webp|avif|JPG|PNG|WEBP|AVIF|JPEG))/;
こんな感じで正規表現を分けることにした。
こうすることで後でメンテナンスがしやすいだろうと判断。
.split()
で商品行に分轄した
次に商品ごとに分けられそうな文字列を見つけた。
今回の場合は const splitText = text.split(/\\n�/);
で分轄した。
分轄した splitText
は
for (let key in splitText) {
const idMatch = idRegex.exec(splitText[key]);
const titleMatch = titleRegex.exec(splitText[key]);
const priceMatch = priceRegex.exec(splitText[key]);
const imageMatch = imageRegex.exec(splitText[key]);
if (idMatch && titleMatch && priceMatch && imageMatch) {
// 処理された使いやすい形式のデータになっている。
}
}
でループを回した。しかし、中にはゴミデータが含まれていた。
ゴミデータを分別した
そこで商品行であることが分かるような特徴的な文字列を見つけ出し、 if (splitText)[key].match(/【ここに特徴的な文字列】/)
で商品行であるかを判別した。
正規表現を調整した
if (priceRegex) {
} else {
console.log(splitText[key]);
}
のようにして不一致だった文字列のどこが問題なのかを見つけて正規表現を修正した。
必要に応じて count++; で成功/失敗の数をカウントしておくと便利だった。
全ての正規表現の実行が成功したものを正データとして取り扱った
if (idMatch && titleMatch && priceMatch && imageMatch) {
これがそう。
どれかが抜け落ちている場合は予期せぬデータの可能性も考えられる。そんなデータは取り扱わないことにした。(今のところ見つかってないが。)
今のところ問題らしい問題は見つかっていない。
上手くいったと思う。