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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

正規表現

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

Q&A

解決済

2回答

869閲覧

Java 正規表現による文字列の抽出について

suteaka

総合スコア13

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

正規表現

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

0グッド

0クリップ

投稿2021/12/22 08:40

編集2021/12/22 08:46

java 正規表現による文字列の抽出について

ここに質問の内容を詳しく書いてください。
javaで正規表現による文字列の抽出を行い、変換するコードを書いています。
例えば「6(iztn2(4i))」について、アルファベットの前の数字はアルファベットを数字分繰り返し、()でくくられているものは()の中身を数字分繰り返したいです。「6(iztn2(4i))」の場合、期待される答えは
「iztniiiiiiiiiztniiiiiiiiiztniiiiiiiiiztniiiiiiiiiztniiiiiiiiiztniiiiiiii」となります。

しかしながら提供したコードで実行すると、返答は「6(iztn2(iiii))」となってしまいます。
コード内のコメント「ここまでは正しいコード」までのコードは正しいと思われますが、その後の正規表現で何か不具合が起きていると思われます。何が間違っているのでしょうか。

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

import java.util.*; import java.util.regex.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String str = sc.next(); String str_p = ""; String str_pa = ""; Integer str_num = 0; String str_char = ""; String regex = "[0-9]+[a-z]"; Pattern p = Pattern.compile(regex); while(true){ Matcher m = p.matcher(str); if (m.find()){ str_p = m.group(); String regex_num = "[0-9]+"; String regex_char = "[a-z]"; String str_a = ""; Pattern p_num = Pattern.compile(regex_num); Pattern p_char = Pattern.compile(regex_char); Matcher mnum = p_num.matcher(str_p); Matcher mchar = p_char.matcher(str_p); if (mnum.find()){ str_num = Integer.parseInt(mnum.group()); } if (mchar.find()){ str_char = mchar.group(); } for(int i=1;i<=str_num;i++){ str_a = str_a + str_char; } str = str.replace(str_p, str_a); }else{ break; } }     /*ここまでは正しいコードと思われる*/ System.out.println(str); String regex_a = "[0-9]+\([a-z]+\)";      /*正規表現がおかしい?*/ Pattern p_a = Pattern.compile(regex_a); while(true){ Matcher m_a = p_a.matcher(str); System.out.println(m_a.find()); if (m_a.find()){ str_pa = m_a.group(); System.out.println(str_pa); String regex_numa = "[0-9]+"; String regex_chara = "[a-z]+"; String str_aa = ""; Pattern p_numa = Pattern.compile(regex_numa); Pattern p_chara = Pattern.compile(regex_chara); Matcher m_numa = p_numa.matcher(str_pa); Matcher m_chara = p_chara.matcher(str_pa); if (m_numa.find()){ str_num = Integer.parseInt(m_numa.group()); } if (m_chara.find()){ str_char = m_chara.group(); } for(int i=1;i<=str_num;i++){ str_aa = str_aa + str_char; } str = str.replace(str_pa, str_aa); }else{ break; } } System.out.println(str); } }

試したこと

「6(iztn6(4i))6(qq)」で試した場合「6(iztn6(iiii))qqqqqqqqqqqq」となり、
「6(iztn6(4i))6(qq2(ai))」で試した場合「6(iztn6(iiii))qqaiaiqqaiaiqqaiaiqqaiaiqqaiaiqqaiai」となりました。
"))"の連続が悪さをしているのかと思ったのですがそうでもなく、なぜか最初の()つきのやつだけ拾ってくれないような感じです。

補足情報(FW/ツールのバージョンなど)

プログラミング初心者のため、汚いコードになっていると思いますが、ご容赦ください。
追加質問などありましたらご連絡ください。

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

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

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

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

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

guest

回答2

0

それほどのコードは必要ありません。
パターンに一致した際の情報は Matcher 内に多数含まれています。
例えば、パターンで () で囲まれた部分で一致した文字列は group(int) で取得できますし、一致した最初の位置、最後の位置(の次)は start(), end() で取得できます。

java

1package teratail_java.q375087; 2 3import java.util.regex.Matcher; 4import java.util.regex.Pattern; 5 6public class Main { 7 public static void main(String[] args) { 8 //try(Scanner sc = new Scanner(System.in);) { 9 // String str = sc.next(); 10 // System.out.println(expansion(str)); 11 //} 12 13 String result = expansion("6(iztn2(4i))"); 14 System.out.println(result); 15 if(result.equals("iztniiiiiiiiiztniiiiiiiiiztniiiiiiiiiztniiiiiiiiiztniiiiiiiiiztniiiiiiii")) { 16 System.out.println("OK."); 17 } else { 18 System.out.println("NG."); 19 } 20 } 21 22 private static final Pattern REPEAT_PATTERN = Pattern.compile("([1-9][0-9]*)(?:([a-zA-Z])|\(([a-zA-Z]+)\))"); 23 24 private static String expansion(String str) { 25 for(Matcher m; (m=REPEAT_PATTERN.matcher(str)).find(); ) { 26 str = reconstruction(str, m.start(), m.end(), 27 Integer.parseInt(m.group(1)), m.group(2)!=null?m.group(2):m.group(3)); 28 } 29 return str; 30 } 31 /** 32 * src の start から end-1 の間を "repeatString を repeatCount 回繰り返した文字列" に置き換えた文字列を返す 33 * @param src 元の文字列 34 * @param start 置き換え開始位置 35 * @param end 置き換え終了位置+1 36 * @param repeatCount 繰り返し回数 37 * @param repeatString 繰り返し文字列 38 * @return 置き換えた文字列 39 */ 40 private static String reconstruction(String src, int start, int end, int repeatCount, String repeatString) { 41 StringBuilder sb = new StringBuilder(src.substring(0, start)); 42 for(int i=0; i<repeatCount; i++) sb.append(repeatString); 43 return sb.append(src.substring(end)).toString(); 44 } 45}

投稿2021/12/22 10:55

編集2021/12/22 12:03
jimbe

総合スコア12545

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

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

0

自己解決

自己解決しました。
m.find()などで前回該当文字列の次から検索されるという性質が悪さをしていると思い、「m.reset();」を組み込んだコードにしたところ無事正しい変換がされました。

投稿2021/12/22 09:24

suteaka

総合スコア13

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

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

jimbe

2021/12/22 20:05

Matcher.find() の名誉の為に書きますと(笑)、 find の2回目が1回目の次から検索するのは「悪さ」ではなく仕様です。 問題なのは、恐らく確認のために入れられたのであろう > System.out.println(m_a.find()); で、不用意に (find の仕様を確認せずに ) if の中身をそのまま使ったせいでしょう。 ですので、この println を無くせば reset しなくても動くのではないでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問