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

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

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

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

Q&A

解決済

3回答

616閲覧

リストに文字列を追加するとき、既に同じ文字列があったら、特定の書式で添え字を付けて追加したい。

jonrock

総合スコア18

C#

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

0グッド

0クリップ

投稿2019/07/19 07:12

下のようなリストがあり、リストの中に "aaa" という文字列を追加しようとした時、
既に同じ文字列があった場合、同じ文字列が入らないようにしたく、
「チルダ(ASCIIコード:7E) + 添え字(19999まで)」
を付与した文字に置き換えて追加したいです。
下の例では、最終的に target の変数の中身を "aaa
4" に置き換えたいです。

List<string> words = new List<string>() { "aaa", "aaa~1", "aaa~2", "bbb", "cdcd", "eee~1", "eee~3", "eee~5", "aaa~3", "ddd~1", "aaa~5", "aaa~12", "aaa~146", "aaa~1559", "aaa ~125", }; string target = "aaa";

考えている手順としては、

・リストの中から「target + チルダ(ASCIIコード:7E) + 4桁以内の数字」 という書式の文字列を抜き出す
・その中からさらに数字のみを抜き出し、空いている添え字の中から最小値を検索する
・「target + チルダ(ASCIIコード:7E) + 検索した添え字」 を作成する

としようと思っているのですが、最初の項目での処理が上手くいきません。
正規表現を使った方がよいのかと感じており、下の様に処理を作成してみました。

static void Main(string[] args) { List<string> words = new List<string>() { "aaa~1", "aaa~2", "bbb", "cdcd", "eee~1", "eee~3", "eee~5", "aaa~3", "ddd~1", "aaa~5", "aaa~12", "aaa~146", "aaa~1559", "aaa ~125", }; string target = "aaa"; List<string> matches = new List<string>(); foreach (string word in words) { if (word.StartsWith(target) && Regex.IsMatch(word, @"[0-9]$") ) { Console.WriteLine(word + " true"); matches.Add(word); } else { Console.WriteLine(word + " false"); } } Console.ReadKey(); }

これだと、末尾に数字があるもの全てがtrue となってしまい、うまく抽出できていませんでした。
ASCIIコードが含まれる場合に、正規表現でどのように表現したらよいかもいまいちわからずで、
ご助言いただけないでしょうか?

宜しくお願い致します。

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

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

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

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

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

guest

回答3

0

正規表現でググった感じですが,

Regex.IsMatch( word, Target+@"~[0-9]{1,4}$" )

とかでそこそこいけませんか?

↑コメントにて,問題点ご指摘を頂きました :
文字列Targetが,正規表現の記述に用いる特殊な文字(何て呼ぶのかわからないけど)を含む場合を考慮していない.
Targetの内容次第では,正規表現の記述として間違った文字列になってしまい,ArgumentExceptionが発生する.


うーん,正規表現だけで抽出する方法は,正直私にはわかりませんでした.
こんな感じで,後段で数値として解釈できるか否かの判定を入れるとか…

foreach( var word in Words ) { if( word.StartsWith(Target) && Regex.IsMatch(word, @"~[1-9][0-9]{0,3}$") ) {//"aaa~2~99"とか"aaa ~125"とかもここに入ってくる Console.Write( word ); uint No = 0; if( uint.TryParse( word.Substring( Target.Length+1 ), out No ) ) { Console.WriteLine( " -> OK : " + No.ToString() ); } else { Console.WriteLine( " -> NG" ); } } }

投稿2019/07/19 07:46

編集2019/07/19 09:17
fana

総合スコア11654

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

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

Zuishin

2019/07/19 07:49

aaa が ... だった場合などに対応できません。
fana

2019/07/19 08:01

"guaaa~50" とかにもマッチしちゃいますね,コレ…
Secret

2019/07/19 08:09

前のAND条件を削ったからではないですか? (word.StartsWith(target) && Regex.IsMatch(word, @"~[0-9]{1,4}$"))
jonrock

2019/07/19 08:14

回答、ありがとうございます。 こちらでも意図した動きにすることができました。 正規表現での記載方法を記していただき、大変参考になります。 ありがとうございました。
fana

2019/07/19 08:17

番号部分が0から始まるやつを除くために @"~[1-9][0-9]{0,3}$" としないとダメかも?
Zuishin

2019/07/19 08:23

こちらも要求仕様を満たしていないのに高評価が入ったので打ち消します。
Zuishin

2019/07/19 08:24

target = "*.(" のようにしてみてください。エラーが出るのではないかと思います。
fana

2019/07/19 08:32

御指摘+正当な評価に関して感謝致します.
fana

2019/07/19 08:45

> target = "*.(" のようにしてみてください。エラーが出るのではないかと思います。 しっかりArgumentException発生しました.
guest

0

ベストアンサー

  1. カウンタに1を代入
  2. 追加文字列がリストにあるか
  3. なければリストに追加、終了。
  4. リストにあれば、追加文字列に~とカウンタ数値を付加
  5. カウンタを+1
  6. 2に戻る

あるかないか、だけでいいので正規表現は不要かも

投稿2019/07/19 07:25

y_waiwai

総合スコア87749

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

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

Zuishin

2019/07/19 07:41

スペースの含まれたものに対応できませんね。あとカウンタに 1 足すたびに全検索するので計算量が大きくなります。
y_waiwai

2019/07/19 07:49

そこまで対応の必要があるのかとか、要求仕様がはっきりしませんが、 まあ、問題が出たときは出たときのことでいいんでは。
jonrock

2019/07/19 08:11

回答、ありがとうございます。 正規表現を使うことに囚われすぎていたようです。 意図した動きになりました。
Zuishin

2019/07/19 08:20 編集

リストにあるので。 > "aaa ~125" これに対応するためにはこの延長線上の方法では無理なので、問題が出たときは出たときのことというのはどうかと思います。
Zuishin

2019/07/19 08:22

高評価入ったので打ち消します。要求仕様を満たしていません。
jonrock

2019/07/19 08:25

指摘、ありがとうございます。 StartsWith(target) での判断に抜けがあるようです。 スペースが含まれたものに関しては除外としたいと思います。
y_waiwai

2019/07/19 08:28

まあ、評価はどーでもいいですが、 "aaa"と"aaa "は別の文字列ということでいいんじゃないでしょうか
fana

2019/07/19 08:41

質問文の雰囲気的に,正規表現を使って達成する方法を問うている話なのかと思ったのですが,そうでもないのですね.
y_waiwai

2019/07/19 08:45

そういう回答もつけていただければいいと思いますよ。 空気を読んで(?)回答つかないより、空気を読まない回答含め、たくさんの解決法が揃うほうが質問くんとかTeratail的にもいいんじゃないかと思っとりますが。 #と、いいわけしてみるw
Zuishin

2019/07/19 08:55

"aaa " はこのデータの中では明らかに一つだけ特異な値であり、テストで言うところの境界値として、仕様の一端を表現しているとみなされます。これを考慮していないということで低評価に一票投じました。この回答の後に、回答に合わせて仕様変更があったようですが、そのようにデータをいじらなくても解決可能であるという理由、計算量が大きいという理由から、評価を戻すつもりはありません。 y_waiwai さんが評価を戻せとおっしゃっているわけではないことは承知しています。これは単なる第三者に向けての説明です。
fana

2019/07/19 09:07

元々,"aaa" と "aaa " とは別の文字列として扱う (この例だと,リスト内に "aaa ~4" が存在していたとしても,リストに追加する文字列は "aaa~4" になる) のだと思っていた.
guest

0

ベストアンサー決まってますが、一応参考までに・・・

文字列を"~"で分割して、前半部分とtargetを比較
スペースが不要なら比較前に削除

一致したら、その文字列を一時的にリストに入れておく
すべての文字列を比較できたら、リストをカウントして0ならtargetをそのままリストに追加
1以上なら、そこから数字部分のみを抜き出して空いてる最小値を検出
targetに"~"+最小値をつけてリストに追加

方法としてはこんなところかと・・・。

追記
fanaさんの追記にある ~ が2つ以上入ったデータが来ると破綻してしまいますね。

投稿2019/07/19 08:38

編集2019/07/19 08:46
k.matsuda

総合スコア293

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問