Java正则表达式:替换字符,除非前面有其他字符
我正在使用Java和正则表达式,需要将一些数据拆分为多个实体。在我的输入中,单引号字符(')指定实体的结尾,除非其前面有转义字符,即问号(?) 我的正则表达式是Java正则表达式:替换字符,除非前面有其他字符,java,regex,Java,Regex,我正在使用Java和正则表达式,需要将一些数据拆分为多个实体。在我的输入中,单引号字符(')指定实体的结尾,除非其前面有转义字符,即问号(?) 我的正则表达式是(?并且我正在使用扫描仪将输入拆分为单独的实体。因此以下情况可以正常工作: Hello'There becomes 2 entities: Hello and There Hello?'There remains 1 entity: Hello?'There 但是,当我遇到想要避开问号的情况时,它不起作用。因此: Hello??'
(?并且我正在使用扫描仪将输入拆分为单独的实体。因此以下情况可以正常工作:
Hello'There becomes 2 entities: Hello and There
Hello?'There remains 1 entity: Hello?'There
但是,当我遇到想要避开问号的情况时,它不起作用。因此:
Hello??'There should become 2 entities: Hello?? and There
Hello???'There should become 1 entity: Hello???'There
Hello????'There should become 2 entities: Hello???? and There
Hello?????'There should become 1 entity: Hello????'There
Hello?????There should become 1 entity: Hello????There
Hello??????There should become 1 entity: Hello?????There
因此,规则是如果有偶数个问号,后跟引号,则应将其拆分。如果有奇数个问号,则不应拆分
有人能帮我修改正则表达式(希望有解释!)来处理多个情况吗
谢谢
Phil尝试此表达式以匹配偶数情况:(?\?\?){01000})
(?\?\?){01000}
表示这些组可以有0到1000个。请注意,您不能编写(?>\?\?)*
,因为表达式需要具有最大长度(最大组数)。但是,根据表达式的其余部分,应该能够将上限增加很多
[^\?](?>\?\?)…
表示两个问号的组前面必须有字符,但不能有问号(否则您将匹配奇数)
您确定要使用正则表达式吗?如果字符串相对较小和/或执行时间不是大问题,则可以使用字符串生成器和循环来计算“?”的数量,例如
//您的字符串
String x=“你好?”'World'Hello?'World”;
StringBuilder sb=新的StringBuilder();
//保持你的分裂
ArrayList parts=新的ArrayList();
int questionmarkcount=0;
国际伊塞文;
for(char c:x.toCharArray()){
如果(c=='?'){
问号计数++;
sb.附加(c);
}else if(c=='\''){
_isEven=questionmarkcount%2;
//如果有偶数个'?,或者没有
如果(_isEven==0 | | questionmarkcount==0){
//添加当前拆分,重置?计数并清除字符串生成器
添加(sb.toString());
sb.删除(0,sb.length());
questionmarkcount=0;
}否则{
//附加问号,不需要拆分
sb.附加(c);
//从头开始数数
questionmarkcount=0;
}
}否则{
sb.附加(c);
}
}
添加(sb.toString());
循环结束时,parts ArrayList将保存所有拆分。如果“.前面有个偶数的问号,则当前代码将被拆分。不要为此使用split()
。这似乎是显而易见的解决方案,但匹配实体本身要比匹配分隔符容易得多。大多数支持正则表达式的语言都有内置的方法,比如Python的findall()
或Ruby的scan()
,但在Java中,我们仍然需要编写样板文件。下面是一个例子:
Pattern p = Pattern.compile("([^?']|\\?.)+");
String[] inputs = {
"Hello??'There",
"Hello???'There",
"Hello????'There",
"Hello?????'There",
"Hello?????There",
"Hello??????There"
};
for (String s : inputs)
{
System.out.printf("%n%s :%n", s);
Matcher m = p.matcher(s);
while (m.find())
{
System.out.printf(" %s%n", m.group());
}
}
输出:
你好???这里:
你好
那里
您好,这里是:
喂
您好,这里是:
你好
那里
您好,这里是:
喂,你在吗
你好?????这里:
喂,在那里
你好,这里:
喂,你好
Thomas使用的任意最大长度的噱头,除了是一个令人厌恶的黑客(无意冒犯,Thomas!),是不可靠的,因为他们不断地在处理这些东西的Pattern.java代码中引入bug。但不要将此解决方案视为另一种解决方法;lookbehinds永远不应该是你的首选,即使是在.NET这样的口味中,它们工作可靠且不受限制。@yzernik这是一个非捕获原子组。如果你省略它,匹配将是?“
而不是”
,也就是说,如果你使用该表达式进行拆分,Hello???那里的将被拆分为Hello
和There
而不是Hello???
和那里的。我不明白你为什么不使用*而不是{01000}“我在回答中解释了这一点。基本上,原因是Java的正则表达式引擎不喜欢任意长度的look behinds(或look aheads)。因此,您必须提供最大长度,这就是为什么提供1000的上限(尽管它可以更高)。-你自己试试看,你会得到这样一条信息,比如非法模式:在索引21附近,Look-behind组没有明显的最大长度(索引21将是星号/星号之前的位置)。有关更多信息,请查看“重要注意事项”这里的部分:更正:Java的lookaheads不受lookbehind的限制。任何有效的正则表达式都可以在lookahead中使用,就像其他所有支持lookaheads的风格一样。“你好吗?”还有一个实体:你好吗?”你认为这是一个正确的例子,是吗?因为你还说“因此,规则是如果有奇数个问号,后面跟一个引号,它应该被拆分”…@ChrisBrautigam从其他例子中,我假设如果你有偶数个问号,后面跟一个引号,那么拆分应该发生。@Thomas哦,是这样的。谢谢,我会从这个角度回答。啊!我把问题搞错了!感谢大家发现我将更新问题,使其正确。谢谢艾伦。我使用了您的解决方案的一个稍加修改的版本,效果非常好。
Pattern p = Pattern.compile("([^?']|\\?.)+");
String[] inputs = {
"Hello??'There",
"Hello???'There",
"Hello????'There",
"Hello?????'There",
"Hello?????There",
"Hello??????There"
};
for (String s : inputs)
{
System.out.printf("%n%s :%n", s);
Matcher m = p.matcher(s);
while (m.find())
{
System.out.printf(" %s%n", m.group());
}
}