返回列表 发帖

泪流满面.................

终于解封了  话不多说  时间有限   提问先..................  牵扯到点JAVA
---------------------------------------------------------------------------


《精通~~~》第三版

P383

原地查找替换这一节

383这页顶头代码 text.replace这一行完全换成,下面关于长度替换有变化的text.replace这一行

代码照样运行 没报错  这是为什么?

代码情况如下:
StringBuilder text = new StringBuilder("it's SO very RUDE to shout!");
Matcher m = Pattern.compile("\\b[\\p{Lu}\\p{Lt}]+\\b").matcher(text);
while(m.find())
{
text.replace(m.start(),m.end(),m.group().toLowerCase());
}
out(text)  我简写了.....

-----------------------------------------------------------------------------------------


StringBuilder text = new StringBuilder("it's SO very RUDE to shout!");
Matcher m = Pattern.compile("\\b[\\p{Lu}\\p{Lt}]+\\b").matcher(text);
int index =0;
while(m.find(index))
{
index=m.end();
text.replace(m.start(),m.end()," <b>"+m.group().toLowerCase()" </b>");
index+=7;
}
out(text)


2段代码都能达到一样的结果,但原书关于第二段代码的说辞是,因为替换的字符长度超过了原始文本,会造成在第一次循环后匹配指针的位置会出错,所以需要手动指定指针位置,而index加的7 则是增加的字符长度


但是现在
StringBuilder text = new StringBuilder("it's SO very RUDE to shout!");
Matcher m = Pattern.compile("\\b[\\p{Lu}\\p{Lt}]+\\b").matcher(text);
while(m.find())
{
text.replace(m.start(),m.end()," <b>"+m.group().toLowerCase()" </b>");
}

就这样  他也没报错,结果也正确

这是为什么?
-----------------------------------------------------------------

这是我上周在问题,现在找到原因,至少是我自认为的原因............

书中给的例子的文本结构刚刚好, 如果在后面再加上更多的大写字符  我的那个测试的代码就出现书中所说的情况了。


但用书中完整的代码又做了几个测试后发现,如果理解书中例子的指针每次循环自家7,那个7代表的是替换后新增的字符<b></b>的长度话。

指针还是自加7,但替换新增的字符长度远远超过7,但仍旧能替换成功,为什么?

这段时间网站打不开,是出了什么问题吗~~~?

对我的提问做个一详细的阐述吧.........

书中 P383 介绍JAVA原地查找替换这一节 上面代码是
  1. StringBuilder text = new StringBuilder("it's SO very RUDE to shout!");
  2. Matcher m = Pattern.compile("\\b[\\p{Lu}\\p{Lt}]+\\b").matcher(text);
  3. while(m.find())
  4. {
  5. text.replace(m.start(),m.end(),m.group().toLowerCase());
  6. }
  7. System.out.println(text);
复制代码
结果是都小写了。

书中下面的代码,是对、替换时增加了一些字符导致匹配指针出错的解决代码
  1. StringBuilder text = new StringBuilder("it's SO very RUDE to shout!");
  2. Matcher m = Pattern.compile("\\b[\\p{Lu}\\p{Lt}]+\\b").matcher(text);
  3. int index =0;
  4. while(m.find(index))
  5. {
  6. index=m.end();
  7. text.replace(m.start(),m.end()," <b>"+m.group().toLowerCase()" </b>");
  8. index+=7;
  9. }
  10. System.out.println(text);
复制代码
我呢~ 去掉了index变量的声明、FIND里的index、循环里自增7这3部分的代码,运行结果还是顶头代码的运行结果一样。

后来我“发现”如果继续扩充原始文本的字符内容,我这测试的代码就不能完全的吧原始文本替换成小写。


现在的问题是,我是把自增的数字7、理解成新增字符的长度"<b></b>"

我原始文本添加了N个大写字母、空格分开,把新增的字符内容增加了  " <asdasdasdasdasdasb>"+m.group().toLowerCase()" </b>");
仍旧能把所有大写都替换成小写 这是为什么?

TOP

1. 我不懂java
2. 晚上回家看看书中是怎么说的。如果我解决不了,就帮你请位高人,呵呵。
在答疑解惑版提问时,请注明所用语言、范例文本、匹配结果。谢谢!
------------------------------------------------------------------------------
我爱正则表达式
GTalk: rex[at]zhasm[dot]com
Twitter: rex_zhasm

TOP

有劳了

能重新打开这个网站 感觉就是好啊~~

TOP

尝试回答如下:
原书这个例子举的不是很恰当,查看Matcher.find()文档可以知道,find()开始的位置是:如果第一次调用或之前调用过,但又调用了reset,则从0开始,否则从上次匹配成功之后的第一个未能匹配的位置开始
我改了一下代码,就可以发现问题
  1.                 StringBuilder text = new StringBuilder("it's SO very RUDE to shout!");
  2.                 Matcher m = Pattern.compile("\\b[\\p{Lu}\\p{Lt}]+\\b").matcher(text);
  3.                 while (m.find()) {
  4.                         text.replace(m.start(), m.end(), "aa");
  5.                         System.out.println(text);
  6.                         System.out.println(text.length());
  7.                 }
复制代码
结果是这样的:
it's aa very RUDE to shout!
27
it's aa very aa to shout!
25
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 25
        at java.lang.AbstractStringBuilder.charAt(Unknown Source)
        at java.lang.Character.codePointAt(Unknown Source)
        at java.util.regex.Pattern$Bound.check(Unknown Source)
        at java.util.regex.Pattern$Bound.match(Unknown Source)
        at java.util.regex.Pattern$Start.match(Unknown Source)
        at java.util.regex.Matcher.search(Unknown Source)
        at java.util.regex.Matcher.find(Unknown Source)
        at temp.REG.main(REG.java:11)

也就是说,如果发生了变长的替换,find()是不知道的,它还会从上次结束的位置+1开始(这也就是range 25异常的原因,此时字符串的长度仅仅为25了,但find还要从偏移值25开始,就产生了越界错误)。
所以,我们需要手动维护match pointer,这样从意义和逻辑上保证程序的正确性(而不仅仅是看某个个例的结果)。
当然,原书的例子也举的不够好,因为就像你指出的,如果不维护match pointer,这里也不会出错,因为替换之后,字符串变长了——如果替换之后字符串变短了,match pointer的作用就凸显出来。

希望这样说你能明白

TOP

楼上正解。

TOP

返回列表