考虑到您的描述,我假设在 "NNDDDDD" 的部分之后,第一个 "A" 实际上会是一个 "N" 而不是 "A",否则 "DDDDD" 和 "AAAA" 之间就没有明确的边界。因此,您的字符串实际上看起来像是 "NNDDDDDNAAA",您想用空格替换 "NAAA" 部分。基于此,正则表达式可以重写为:"(\\D+\\d+)(\\D.+)"。
Java 中的正向回顾需要一个固定长度的模式;您不能使用 "+" 或 "*" 模式。相反,您可以使用花括号并指定最大长度。例如,您可以使用 "{1,9}" 来代替每个 "+",它将匹配 1 到 9 个字符:"(?<=\\D{1,9}\\d{1,9})(\\D.+)"
这里唯一的问题是,您将 NAAA 序列作为单个匹配项进行匹配,因此使用 "NNNDDDDNAAA".replaceAll("(?<=\\D{1,9}\\d{1,9})(\\D.+)", " ") 将导致用单个空格替换整个 "NAAA" 序列,而不是多个空格。
您可以采取匹配的开始定界符和字符串长度,并使用它来附加正确数量的空格,但我认为这没有意义。我认为您最好使用原始解决方案;它简单易懂。
如果您想要更快的速度,可以在函数外编译您的 Pattern,并使用 StringBuilder 或 StringBuffer 来创建输出。如果您正在从所有这些 NNDDDDDAAAAA 元素中构建一个大字符串,请完全使用 StringBuilder 直到您完成附加。
class Test {
public static Pattern p = Pattern.compile("(\\D+\\d+)(\\D.+)");
public static StringBuffer replace( String input ) {
StringBuffer output = new StringBuffer();
Matcher m = Test.p.matcher(input);
if( m.matches() )
output.append( m.group(1) ).append( m.group(2).replaceAll("."," ") );
return output;
}
public static void main( String[] args ) {
String input = args[0];
long startTime;
StringBuffer tests = new StringBuffer();
startTime = System.currentTimeMillis();
for( int i = 0; i < 50; i++)
{
tests.append( "Input -> Output: '" );
tests.append( input );
tests.append( "' -> '" );
tests.append( Test.replace( input ) );
tests.append( "'\n" );
}
System.out.println( tests.toString() );
System.out.println( "\n" + (System.currentTimeMillis()-startTime));
}
}
更新:
我写了一个快速迭代的解决方案,并对两种方法运行了一些随机数据。这个迭代解决方案大约快了4-5倍。
public static StringBuffer replace( String input )
{
StringBuffer output = new StringBuffer();
boolean second = false, third = false;
for( int i = 0; i < input.length(); i++ )
{
if( !second && Character.isDigit(input.charAt(i)) )
second = true;
if( second && !third && Character.isLetter(input.charAt(i)) )
third = true;
if( second && third )
output.append( ' ' );
else
output.append( input.charAt(i) );
}
return output;
}