引用符で囲まれていない単語を置き換えたい。
どのように動作する必要があります:
「ヒーロー」 - 変わらない
「あなたはスーパーヒーロー」 - 変わらない
私はヒーローです-変更
あなたはスーパーヒーローです-変更
私は試した
word = word.replaceAll("(?!\")(.*)hero(.*)(?!\")","$1 zero $2")
- しかし、うまくいきません
この正規表現はあなたのために働くはずです:
hero(?=(?:(?:[^\"]*\"){2})*[^\"]*$)
説明:
これは基本的にhero
、偶数個の二重引用符が続く場合、リテラル テキスト ( ) に一致することを意味します。つまり、二重引用符の外側にある場合、目的のテキストに一致します。
テスト:
String str = "hero \"dont-hero\"";
String repl = str.replaceAll("hero(?=(?:(?:[^\"]*\"){2})*[^\"]*$)", "FOO");
//repl = FOO "dont-hero"
あなたの質問は明確ではありません。任意の数のネストされた引用符を処理したいですか? もしそうなら、どのように?たとえば、次の入力で何をしたいですか?
I hate it when people say "you are such a "hero"!"
ここで引用符で囲まれた「ヒーロー」という言葉はありますか?または、「you are such a 」というフレーズを引用符で囲み、その後に引用符で囲まれていない単語「hero」を続け、その後に「!」を続けます。引用符で?
しかし、さらに単純なケース
"hello" said the boring old "cat", are you really a "hero"?
おそらく、正規表現では達成できないでしょう。少なくとも、それを価値のあるものにする正気の方法ではありません。
受け入れられた答えは、完全に非直感的な方法で失敗します
I will be your "hero" baby! O"RLY?
何らかのコードで文字列を解析してみませんか?
正規表現を使用するよりも、次の方法が適していると思います。
class Main {
public static String replace(String str, String origstr, String newstr) {
StringBuilder result = new StringBuilder();
int lastIdx = 0;
boolean inquotes = false;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '"') {
if (inquotes) {
inquotes = false;
result.append(str.substring(lastIdx, i+1));
} else {
result.append(str.substring(lastIdx, i+1).replace(origstr, newstr));
inquotes = true;
}
lastIdx = i+1;
}
}
result.append(str.substring(lastIdx, str.length()).replace(origstr, newstr));
return result.toString();
}
public static void main (String[] args) throws java.lang.Exception {
System.out.println(replace("", "change", "___"));
System.out.println(replace("\"dont-change\"", "change", "___"));
System.out.println(replace("\"change", "change", "___"));
System.out.println(replace("simple: change", "change", "___"));
System.out.println(replace("simple2: \"dont-change\"", "change", "___"));
System.out.println(replace("change \"dont-change\"\"", "change", "___"));
System.out.println(replace("change \"dont-change\"", "change", "___"));
System.out.println(replace("\"dont-change\" change", "change", "___"));
}
}
正規表現を使用する方法。
アイデアは、キャプチャグループに入れたターゲット単語の前の引用符の間のすべての部分文字列を一致させることです。次に、キャプチャ グループ オフセットを使用して、対象の単語を含む部分文字列を置き換えます。
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class quotyquot {
public static void main(String[] args) {
String s = "I am super hero here and now\n"
+"Superman is an incredible hero\n"
+"I am super \"hero\" here and now\n"
+"\"I am super hero here and now\"";
String t = "hero"; // target
String r = "zero"; // replacement
Integer d = r.length() - t.length();
Integer o = 0; // offset
Pattern p = Pattern.compile("\"[^\"]*\"|(" + t + ")");
Matcher m = p.matcher(s);
while (m.find()) {
if (m.group(1)!=null) {
s= s.substring(0, m.start() - o) + r + s.substring(m.end() - o);
o -= d;
}
}
System.out.println(s);
}
}
分割を使用する別の方法:
String t = "hero"; // target
String r = "zero"; // replacement
int c=0; // switch
String[] pi = s.split("(?=hero|\")|(?<=hero|\")");
String result = "";
for (int i=0; i<pi.length;i++) {
if (c==0 && pi[i].equals(t))
pi[i]=r;
else if (pi[i].equals("\""))
c = 1 - c;
result += pi[i];
}
System.out.println(result);