正则表达式替换逗号分隔列表中的冒号前缀,但引用除外

时间:2013-01-22 17:24:15

标签: regex

我希望有一个正则表达式用冒号(:)替换冒号(?),如下所示。
但如果它们位于单引号')内,它应该保留冒号。

例如,此输入字符串:

(:a,:abc,'quoted with :colon, and comma',:more)

应改为:

(?a,?abc,'quoted with :colon, and comma',?more)

3 个答案:

答案 0 :(得分:2)

String str = "(:a,:abc,'quoted with :colon, and comma',:more)";
StringBuffer sb = new StringBuffer();
boolean inQuote = false;
for (char c : str.toCharArray()) {
    if (c == '\'') {
        inQuote = !inQuote;
        sb.append(c);
    } else if (inQuote) {
        sb.append(c);
    } else if(c == ':') {
        sb.append('?');
    } else {
        sb.append(c);
    }
}
str = sb.toString();
System.out.println(str);

生成(?a,?abc,'quoted with :colon, and comma',?more)的预期输出。但是,它显然没有使用正则表达式。另外请记住,如果您允许转义引号,我的解决方案将会失败。

答案 1 :(得分:1)

您可以替换: even numbers之后的所有quotes (')。它至少适用于这种情况: -

String str = "(:a,:abc,'quoted with :colon, and comma',:more)";     
str = str.replaceAll("[:](?=(?:[^']*'[^']*')*[^']*$)", "?");

System.out.println(str);

输出: -

(?a,?abc,'quoted with :colon, and comma',?more)

因此,:内的quotes将永远不会跟随偶数quotes,因为您有每个开头报价的收盘价,因此它不会被?替换。

答案 2 :(得分:1)

这是另一种适用于replaceAll的解决方案。

原始正则表达式:

((?:^\(|\G)(?: *'(?:[^'\\]|\\.)*' *,| *[^:' ][^,]* *,)* *):([^,]* *(?:,|\)$))

引用字符串(在replaceAll中使用):

"((?:^\\(|\\G)(?: *'(?:[^'\\\\]|\\\\.)*' *,| *[^:' ][^,]* *,)* *):([^,]* *(?:,|\\)$))"

替换(在replaceAll中使用):

"$1?$2"

示例输入:

(  :a  ,  :abc,  'quoted with :colon, and comma', skdhfks'sdfkdf  , :sdf, 'sdfds\'f', :sdfksdf, sdkhfksd , :dfsd,  sdfk'fjsdhfkf, 'werwer', :sdf, :Sdf, skhfskjdf, 'asdads\' :asdkahsd ad'   )

示例输出:

(  ?a  ,  ?abc,  'quoted with :colon, and comma', skdhfks'sdfkdf  , ?sdf, 'sdfds\'f', ?sdfksdf, sdkhfksd , ?dfsd,  sdfk'fjsdhfkf, 'werwer', ?sdf, ?Sdf, skhfskjdf, 'asdads\' :asdkahsd ad'   )

基本上,,之前和之后的空格是自由允许的。如果'不是第一个字符,则不会将其视为带引号的字符串。允许在引用的字符串内转义' - 实际上允许使用\进行任何类型的转义。不允许空参数,例如(:a, , :b)

DEMO

如果没有详细的文字说明,我会在这里做一些疯狂的假设。

<强>解释

为了便于说明。我将删除一些捕获组(),这只对替换有用。

(?:^\(|\G)(?: *'(?:[^'\\]|\\.)*' *,| *[^:' ][^,]* *,)* *:[^,]* *(?:,|\)$)

将它分开(注意前面有些行有空格,它是正则表达式的一部分):

(?:^\(|\G)
(?:
 *'(?:[^'\\]|\\.)*' *,
|
 *[^:' ][^,]* *,
)*
 *:[^,]* *
(?:,|\)$)

正则表达式的每个匹配将包含:不应替换的标记,后跟需要替换的单个标记。

正则表达式从(?:^\(|\G)开始,它将匹配字符串开头的(,或从上一个匹配\G的位置继续。

不应替换的标记是引用的字符串'(?:[^'\\]|\\.)*'[^:' ][^,]*文本序列,不以':开头,并且不包含逗号,。我允许使用\\.在引用的字符串中转义,这意味着\后跟任何字符。我*允许任意数量的不感兴趣的令牌。

你可以看到*之后的空格,这意味着我允许在令牌之前和之后的任意间距。

然后我们感兴趣的令牌::[^,]*

然后正则表达式以(?:,|\)$)结束,这意味着它在最后遇到),或者,。这个结尾部分是\G工作所必需的。