【问题标题】:Java Replace Questionmarks not surrounded by quotesJava替换不被引号包围的问号
【发布时间】:2016-04-14 22:39:19
【问题描述】:

我正在用不同的值替换字符串中的问号。

例子:

String: "XYZ(?,?,?)"

Values: [1, 'Text', 0.5]

Result: XYZ(1,'Text', 0.5)

我的 Preudo 代码:

String s = "XYZ(?,?,?)";
for(int i = 0; i < array.lengh; i++){
   s = s.replaceFirst("\\?",array[i]);
}

通常这很好用。但有时我的值中有一个问号,例如:值:[1,'Question?',0.5]。那么我的结果是:XYZ(1,'Question0.5', ?)。这是因为该函数替换了前一次迭代替换文本的问号。

如何告诉函数只替换没有被引号包围的问号?什么是正确的正则表达式?

【问题讨论】:

  • 你的伪代码应该是s = s.replaceFirst(regex, replacement);?

标签: java regex string replace


【解决方案1】:

如果您不必使用正则表达式或替换,那如何?

String s = "XYZ(?,?,?)";
String[] tokens = s.split("\\?");
s = "";
for(int i = 0; i < array.length; i++){
   s += tokens[i] + array[i];
}
s += tokens[array.length];

(编辑:转义?在正则表达式中,长度有一个 t,最后插入后需要部分)

如果可能有额外的问号,这比要插入的值的数量多,并且您希望像 OP 代码那样保留额外的问号和它们后面的任何文本,请限制 split

String[] tokens = s.split("\\?", array.length+1);

如果问号的数量或结果的总大小(模板字符串加上插入)很大,重复的字符串连接性能很差;改用StringBuilder

StringBuilder b = new StringBuilder (s.length()+estimated_expansion);
// this estimate doesn't have to be correct, but if it is high enough 
// without being *much* too high performance is optimized
for(int i = 0; i < array.length; i++ ){
  b.append(tokens[i]).append(array[i]);
}
s = b.append(tokens[array.length]).toString();

【讨论】:

  • 这将导致同样的问题,如果任何问题被引号包围,那么这并不能解决 OP 问题。
  • @chsdk 不,它不会导致同样的问题。这是一个有效的解决方案。
  • @UtkuÖzdemir 啊,是的,你是对的,我的错,我错过了字符串将被拆分一次,然后将被精细替换。
  • @Utku 不重新扫描问号是有效的,但它有一些小错误: JCheong:我编辑了 3 个小错误和 2 个可能的改进;如果您不同意,请随时恢复或重新编辑。
  • @dave_thompson_085 感谢伟大的代码。我也学到了很多
【解决方案2】:

您可以先将所有问号替换为%s,然后再使用String.format(input, args...)。像这样的:

Object[] array = {1, "Test", 0.5};
String s = "XYZ(?,?,?)";

String output = String.format(s.replace("?", "%s"), array);
System.out.println(output);

会给你这个输出:

XYZ(1,Test,0.5)

另外,请注意,在您的问题中,您的 s.replaceFirst("\\?",array[i]); 调用无效,因为在 Java 中字符串是不可变的,并且对字符串的所有操作(例如替换)都会返回一个新字符串,您应该使用返回的字符串。

另一个注意事项:字符串应该用双引号而不是单引号。

【讨论】:

    【解决方案3】:

    下面编码的更直接的方法怎么样?

    public class Replacer {
        static String replace(String s, String[] values) {
            StringBuffer sb = new StringBuffer();
            for (int i = 0, j = 0; i < s.length(); i ++) {
                char c = s.charAt(i);
                if (c != '?')
                    sb.append(c);
                else
                    sb.append(values[j++]);
            }
            return sb.toString();
        }
    
        public static void main(String[] args) {
            System.out.println(replace("XYZ(?, ?, ?)", new String[]{"1", "Question?", "0.5"}));
            System.out.println(replace("XYZ(?, ?, ?)", new String[]{"foo", "bar", "baz"}));
        }
    }
    

    打印出来:

    XYZ(1, Question?, 0.5)
    XYZ(foo, bar, baz)
    

    【讨论】:

      【解决方案4】:

      你可以使用这个正则表达式:

      String regex = "\\?(?=[^']+$)";  
      

      这个想法是当您调用s.replaceFirst(regex, str) 时,第一个"?" 后面不能跟引号,不能在引号内。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-30
        • 2017-09-11
        • 2020-10-01
        • 1970-01-01
        • 2023-04-07
        • 1970-01-01
        • 2014-10-17
        • 1970-01-01
        相关资源
        最近更新 更多