質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

正規表現

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

1254閲覧

Unity C#でスクレイピングしたデータから正規表現でマッチした文字列の位置までの情報全てを取得したい

Etizen.K

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

正規表現

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2021/03/26 14:41

編集2021/03/26 18:09

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.Networking; 5 6public class htmlget : MonoBehaviour { 7 8void Start () { 9 StartCoroutine(GetText()); 10     } 11 12 IEnumerator GetText() 13 { 14 UnityWebRequest www = UnityWebRequest.Get(link); 15 yield return www.SendWebRequest(); 16 17 if (www.isNetworkError || www.isHttpError) 18 { 19 Debug.Log(www.error); 20 } 21 else 22 { 23 byte[] results = www.downloadHandler.data; 24 } 25 26System.Text.RegularExpressions.Regex num = 27 new System.Text.RegularExpressions.Regex( 28 @"[0-9]+", 29 System.Text.RegularExpressions.RegexOptions.IgnoreCase 30 | System.Text.RegularExpressions.RegexOptions.Multiline); 31 32System.Text.RegularExpressions.Regex alphabet = 33 new System.Text.RegularExpressions.Regex( 34 @"[a-zA-Z]+", 35 System.Text.RegularExpressions.RegexOptions.IgnoreCase 36 | System.Text.RegularExpressions.RegexOptions.Multiline); 37 38 39バイナリーデータの中身(例) 40 41あいうえお 4212345 43 44かきくけこ 4512345 46 47ABCDE 48 49あいうえお 5012345 51 52かきくけこ 5312345 54 55```### 前提・実現したいこと 56 57バイナリーデータから 58アルファベットの位置までの数字(ABCDEより上の位置の数字)を正規表現で全てマッチさせて 59MatchCollectionを作成しそれを配列に変換したいのですが 60 611.正規表現だけでそれが可能かどうか 62 632.一度アルファベットの位置(ABCDEの位置)を取得して正規表現以外でその位置までで検索を止める方法 64 65どちらのやり方でできるのか教えてほしいです。 66 67### 発生している問題・エラーメッセージ 68 69正規表現で数字をマッチさせようとするとアルファベットの位置(ABCDE)より下の位置の数字までマッチさせてしまう。 70 71### 試したこと 72 73正規表現一行で 74アルファベットの位置(ABCDE)を末尾指定$マーク等でアンカーをつけたりしたがそうすると数字もマッチしなくなる。 75 76大雑把な例 770-9+[a-zA-Z]+$ 78 79### 補足情報(FW/ツールのバージョンなど) 80 81 82 83ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

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

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

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

rtazaki

2021/03/26 16:10

新参者なのでよくわかっていませんが、 回答を書く前に質問への追記・修正依頼をすることが推奨されていますか? (齟齬をなくそうという意図でしょうか?回答0のままコメント欄が伸びている質問を多く見かけます。) ↓回答は回答欄に入力しましょう に従い、先に回答を書いてしまいました。
rtazaki

2021/03/26 16:28

回答欄にも書きましたが、文字、文字列、数字、アルファベットの仕様をもう少し補足して下さい。 (できればcodeブロックを使っていただけないでしょうか。) * 複数行の文字列がstringなのかList<string>なのか? * ファイルから引っ張るのか、コード内埋め込みなのか、別アプリから通信で取るデータなのか? * 取得したい数字は全角/半角含んで良いのか? * stringで取りたいのかchar配列で取りたいのか? * 正規表現はmustか? 文字列をSelectもしくはSelectManyで文字として射影して、 Char.IsNumberやChar.IsDigit、Char.IsLetterやChar.IsUpper、Char.IsLowerを使うのも手です。
Etizen.K

2021/03/26 18:19

回答ありがとうございます!より詳しく編集しましたのでご指導よろしくお願いします! 正規表現でマッチさせたい情報にマッチさせるregexは作れて全てマッチさせる事は出来たのですが途中で検索を止めたりすることができなくて困っています・・・
退会済みユーザー

退会済みユーザー

2021/03/26 23:37 編集

> 新参者なのでよくわかっていませんが、 回答を書く前に質問への追記・修正依頼をすることが推奨されていますか? 例えば、情報不足の質問に対し、回答者が想像を膨らませて回答すると、想像が違っていた場合は的外れな回答になって混乱を招くばかりということになり勝ちなので、不明点はきちんと確認して質問者さんに質問欄を編集して情報を追記してもらうべきと思います。 他に「XY問題」になっていて、いくら回答してもいっこうに解決しないというケースもよくあります。(XY問題が何か不明ならググってください) それゆえここが「質問への追記・修正の依頼」として提供されていると理解しています。
rtazaki

2021/03/27 14:09

「XY問題」ググりました。すごく心当たりがあります。大変参考になりました。 マズローのハンマーですね。「金槌しか持っていなければ、全ての問題は釘に見えてくる」 Linqにこだわるのも、正規表現にこだわるのも止めてみます。
rtazaki

2021/03/27 14:28

バイナリーデータの仕様について、再度確認させてください。 * 改行コードはどのように入っていますか? * ABCDEは、必ず同じキーワードでしょうか? * ABCDEは、必ず単数とわかっていますか? * ABCDEより前の数値がすべて半角の12345ですし、ABCDEより後の数値も12345なのですが、 12345,12345を取得できれば良いですか。
Etizen.K

2021/03/27 17:44

申し訳ないのですがバイナリーデータがどのようなものか私がよく理解していないので、あれから試してみた事、やりたい事を書きます。 バイナリーデータから正規表現でマッチするときに\nで改行文字をマッチさせる事ができます。空白文字も\sでマッチさせることができたのでHTMLファイルとテキストファイルのような構造になっていると思います(間違ってる可能性大なので参考程度にお願いします) *ABCDEは必ず同じキーワードで単数です。 *数字はすべて半角です。 *ABCDEより前の位置にある数字を取得したいです。 *ABCDEより後の位置にある数字は必要ないのでマッチさせたくないです。 私のやりたい事がrtazakiさんが最初に書いてくれたソースの中の.TakeWhileと.Whereを使う事で目的を果たせそうな気がします。 試してみた事は バイナリーデータから直接.takewhile.Wheleを使おうとしたらエラーになる var get = www.downloadHandler.text. TakeWhile(line => !stop.IsMatch(line)). Where(target => r.IsMatch(target)); で試すと!stop.IsMatch(line)).の(line)の箇所でCS1503:引数1:はcharから stringへ変換する事ができません。となる なので一旦バイナリーデータから数字とアルファベットをマッチさせてから .takewhile.Wheleを使おうとしたのですが上手くできなかったです。 正規表現でregexを作りmatchesでバイナリーデータからマッチコレクションmcを作る マッチコレクションmcの中身が 12345 12345 ABCDE 12345 12345 であることを確認してforを使ってmcの中身を文字列にして配列に変換する var hairetu = new string[mc.Count]; for (int i = 0; i < hairetu.Length; i++) { hairetu[i] = mc[i].ToString(); } そしてhairetuに対して.takewhile.Wheleを試してみてもうまくいきませんでした。 var gool = hairetu. TakeWhile(line => !stop.IsMatch(line)). Where(target => r.IsMatch(target)); 1番やりたい事はバイナリーデータから正規表現で目的の配列を作るです。 hairetu[0] = 12345 hairetu[1] = 12345 という感じです。 もし直接バイナリーデータから配列が作れない時はMatchesを使い マッチコレクションを作ってから配列に変換したいと考えています。 プログラミングの知識が未熟で説明も下手ですがご教示くださると助かります。
退会済みユーザー

退会済みユーザー

2021/03/27 23:44

> HTMLファイルとテキストファイルのような構造になっていると思います(間違ってる可能性大なので参考程度にお願いします) ひょっとして JSON 文字列になっているとかでは? だとすると、XY問題になっていると思います。
rtazaki

2021/03/28 05:42

バイナリデータ: 包含関係の罠付きなのでご注意ください。 バイナリでググってみるとわかりますが、コンピューターが扱えるすべてのデータ=バイナリデータなので、テキストデータはバイナリーデータに含まれます。スクレイピングしたデータがバイナリーデータというのはその意味で「バイナリ」と言っています。(テキストしか送受信できないWebシステムって、使い道として限定的過ぎますよね?) ところが、実際に扱うものがすべてバイナリだと本当に面倒くさいんですよ。今回のようなケースで、至高の正規表現マスター(笑)が「2回に分けずとも1回で目的のデータを取得してみせた」としても、究極のLinqプログラマー(笑)が、「それだと1回で取得するメモリサイズが大きいとソフトが死ぬので、ある程度の大きさごとに分割して、目的のデータを逐一返すのが真理」とか言っちゃっても、 普通のWebプログラマーならば受信したデータ=Json(もしくはXML)と分かっているので、適切なパーサーを用意するだけで目的を達成できてしまうのです。 Jsonであれば、System.Text.JsonもしくはNewtonsoft.Jsonをnugetして、そのバイナリをシリアライズ してみてください。 ヒントを出しておきます: スクレイピングしたデータにはそれを納めるためのデータ構造があります。 c# json シリアライズ クラス
guest

回答2

0

自己解決

rtazakiさん、SurferOnWwwさん回答いただきありがとうございました。
json関連を調べてみたのですが私には難しすぎてよくわかりませんでした。
なのでもう一度目的とそれを達成する為の手段を最初から見直したところ全く別のアプローチで解決することができました。
一応私が作りたかった配列は作れたので無駄な処理があるかもしれませんが書いておきます。

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.Networking; 5 6public class htmlget : MonoBehaviour { 7 8void Start () { 9 StartCoroutine(GetText()); 10     } 11 12 IEnumerator GetText() 13 { 14 UnityWebRequest www = UnityWebRequest.Get(link); 15 yield return www.SendWebRequest(); 16 17 if (www.isNetworkError || www.isHttpError) 18 { 19 Debug.Log(www.error); 20 } 21 else 22 { 23 byte[] results = www.downloadHandler.data; 24 } 25 26System.Text.RegularExpressions.Regex num = 27 new System.Text.RegularExpressions.Regex( 28 @"(?<num>[0-9]+)|(?<num>[a-zA-Z]+)", 29 System.Text.RegularExpressions.RegexOptions.IgnoreCase 30 | System.Text.RegularExpressions.RegexOptions.Multiline); 31 32 System.Text.RegularExpressions.MatchCollection mc = num.Matches(www.downloadHandler.text); 33 34int stopline = 0; 35var databox = new string[mc.Count]; 36 37 for (int i = 0; i < databox.Length; i++) 38 { 39 databox[i] = mc[i].Groups["num"].ToString(); 40 } 41 42 foreach (var m in detabox.Select((Value, Index) => new { Value, Index })) 43 { 44 if(m.Value.Contains("ABCDE")) 45 { 46 stopline = m.Index; 47 } 48 } 49 50string[] hairetu; 51 52for(int i = 0; i < stopline ; i++) 53{ 54 hairetu[i] = databox[i]; 55} 56 57 58バイナリーデータの中身(例) 59 60あいうえお 6112345 62 63かきくけこ 6412345 65 66ABCDE 67 68あいうえお 6912345 70 71かきくけこ 7212345

正規表現でグループ指定したのは必要な情報を取得するのと
以降は不必要な情報になる位置のABCDEの文字列をわかりやすい単語にして抜き取るためです。

かなり無駄が多い処理になったとはいえ目的が達せられたので良かったです。

未熟な私にお二方の貴重な時間を割いていただきありがとうございました!

投稿2021/03/28 12:29

Etizen.K

総合スコア0

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

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

rtazaki

2021/03/28 13:05

目的達成できたのであれば良かったです。お疲れ様でした!
guest

0

  1. List<string>ではなく、string@"ここに改行を含んだ文字列"だったら、

文字列リストに突っ込む作業が必要です。(そこは未調査です。)

  1. 数字は全角/半角/両方のどれでしょう?(正規表現で全対応しています。)

  2. 数字(ABCDEより上の位置の数字)を正規表現で全てマッチさせ取得の部分が^数字$なので、

すべて数字の文字列を取得しています。これが、12あ45→1245を拾いたいとかの場合は
未調査です。


ソースの説明

.TakeWhileの部分で、アルファベットの位置までの全行を取得し、
.Whereで数字だけの行を取り出しています。

c#

1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Text.RegularExpressions; 5 6namespace test 7{ 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 var list = new List<string> 13 { 14 "あいうえお", 15 "12345", 16 "", 17 "かきくけこ", 18 "56789", 19 "", 20 "ABCDE", 21 "", 22 "あいうえお", 23 "12345", 24 "", 25 "かきくけこ", 26 "56789", 27 }; 28 var alphabet = new Regex(@"^[a-zA-Z]+$"); 29 var num = new Regex(@"^[0-9\d]+$"); 30 var matchlines = list 31 .TakeWhile(line => !alphabet.IsMatch(line)) 32 .Where(target => num.IsMatch(target)); 33 foreach (var match in matchlines) 34 { 35 Console.WriteLine(match); 36 } 37 } 38 } 39}

投稿2021/03/26 15:57

rtazaki

総合スコア69

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問