2009-12-11 86 views
1

使用正则表达式,我同时使用正则表达式陷入了一个问题。 我的要求是:拆分长串入的125个字母的最大尺寸,然后插入一行打破它们之间。 分裂时,它不应该在单词之间分裂。简而言之,我想将字符串拆分为长度为125的小字符串或125字母之前的单词末尾。希望我没有困惑模式错误而在Java

我用一个正则表达式来解决这个问题,相信我是在这样的一个绝对零度。 我刚刚得到一个代码,并复制粘贴;-)

StringBuffer result = null; 
while(mailBody.trim().length() > 0){ 
    Matcher m = Pattern.compile("^.{0,125}\\b").matcher(mailBody); 
    m.find(); 
    String oneLineString = m.group(0); 
    if(result == null) 
     result = new StringBuffer(oneLineString); 
    else 
     result.append("\n"+ oneLineString); 
    mailBody = mailBody.substring(oneLineString.length(), 
            mailBody.length()).trim(); 
}  

这是我的代码,除非开始串上了一个句号结束它的正常使用()。 在这种情况下,它会发出如下错误:未找到匹配项。

请帮忙。

问候, Anoop的pk

回答

1

你可以尝试使用下面的呢?

Matcher m = Pattern.compile("(?:^.{0,125}\\b)|(?:^.{0,125}$)").matcher(mailBody); 

在这里,我们使用您的原始匹配或我们匹配一个字符串,其总长度为125个字符或更少。 (?:X)项目是非捕获组,因此我可以使用|运营商在大型集团。

See documentation for the Pattern class here


附录: @Anoop:没错,有不放过句末标点在自己的行是不可取的行为。你可以代替试试这个:

if(result == null) 
    result = new StringBuffer(""); 

mailBody = mailBody.trim(); 

while(mailBody.length() > 125) { 

    // Try not to break immediately before closing punctuation 
    Matcher m = Pattern.compile("^.{1,125}\\b(?![-\\.?;&)])").matcher(mailBody); 
    String oneLineString; 

    // Found a safe place to break string 
    if (m.find()) { 

     oneLineString = m.group(0); 

    // Forced to break string in an ugly fashion 
    } else { 

     // Try to break at any word boundary at least 
     m = Pattern.compile("^.{1,125}\\b").matcher(mailBody); 

     if (m.find()) { 

      oneLineString = m.group(0); 

     // Last ditch scenario, just break at 125 characters 
     } else { 

      oneLineString = mailBody.substring(0,124); 

     } 

    } 

    result.append(oneLineString + "\n"); 
    mailBody = mailBody.substring(oneLineString.length(), 
            mailBody.length()).trim(); 
} 

result.append(mailBody); 
+0

嗨巴迪, 完美!现在错误消失了。但另一个概念来了,最后一个句号即将进入下一行。甚至没有完全停止,因为最后一个字符或一系列这样的字符在新行中出现的任何特殊字符 – Anoop 2009-12-11 06:43:48

+0

扩展了函数以更好地处理短字符串和有问题的字符串。在第一个匹配中添加了否定性前瞻断言,以避免在句子结束标点符号处出现断裂,并在情况下只有一个长度超过125个字符的文本块时使用后退功能。此外,使最小匹配距离为1,而不是0,以避免出现像125个字符之后的字符串等问题。 – 2009-12-12 06:24:07

1

而不是直接使用正则表达式,可以考虑使用java.text.BreakIterator中 - 这就是它的设计。

+0

这将在performancewise更好?正则表达式或breakIterator。我实际上是用BreakIterator开始的,但我遇到了一些困难。因此切换到 – Anoop 2009-12-11 06:47:09

1

首先,技术上可以得到一个简单的模式,这使得你的意图更加明显lookingAt()方法相同的结果。另外,将模式编译从循环中移出是很好的做法。

我觉得你的正则表达式是好的,虽然简单,但是你可能需要明确定义您通过一个字休息的意思,而不是依靠什么词边界的机构。这听起来像是你想捕捉这段时期,然后打破,但\ b不会那样做。您可以在空白而不是打破...

编辑:即使是现在更简单...

StringBuilder result = null; 
Pattern pattern = Pattern.compile(".{0,125}\\s|.{0,125}"); 
Matcher m = pattern.matcher(mailBody); 
while(m.find()) { 
    String s = m.group(0).trim(); 
    if(result == null) { 
     result = new StringBuilder(s); 
    } else { 
     result.append(s); 
    } 
} 

...我认为改进后的新的编辑甚至是简单,还是做你想做的。

模式可以,如果有,将被认为是易碎的其他字符进行调整:

Pattern.compile(".{0,125}[\\s+&]|.{0,125}"); 

...等等。这将使上的空白符,+字符,并&字符作为一个例子。

2

我还不能评论,给出的答案是好的。我想补充一点,你应该在循环之前初始化的StringBuffer和减少复制,启动它至少与你原来的字符串,像这样:

StringBuffer result = new StringBuffer(mailBody.length()); 

然后在循环就没有必要检查result == null

编辑:于PSpeed答案评论... 需要在每一个新行添加新行添加到匹配原始,像这样(假设结果已被初始化为我建议):

while (m.find()) { 
    if (result.length() > 0) 
     result.append("\n"); 
    result.append(m.group().trim()); 
} 
0

这个异常不是由你的正则表达式引起的,这是因为你错误地使用了API。在拨打group()之前,您应该检查find()方法的返回值 - 这就是您知道匹配成功的方式。

编辑:这是发生了什么事情:当你到达最后一块文本时,正则表达式最初匹配所有的方式到最后。但\b不能在该位置匹配,因为最后一个字符是句号(或句号),而不是单词字符。所以它回退一个位置,然后\b可以匹配最后一封信和期间。

然后它尝试匹配另一个块,因为mailBody.trim().length()仍然大于零。但是这次根本没有单词字符,所以匹配尝试失败,并且m.find()返回false。但是您不检查返回值,您只需继续并调用m.group(0),这会正确引发异常。您应该使用m.find()作为while条件,而不是具有字符串长度的业务。

事实上,你正在做的工作比你需要的多得多;如果您使用API​​正确,你可以降低代码的一个行:

mailBody = mailBody.replaceAll(
    "\\G(\\w{125}|.{1,123}(?<=\\w\\b)[.,!?;:/\"-]*)\\s*", 
    "$1\n").trim(); 

正则表达式是不完美的 - 我不认为这是可能的 - 但它可能做的不够好。

+0

他正确使用它。 (尝试自己运行代码并查看。)组0是整个匹配模式,这是正则表达式库的常见行为。 (即使Perl有$ 0是整个匹配模式) – 2009-12-13 12:04:21

+0

我没有说他不应该使用group(0)或group(),我说他应该检查m.find的返回值()'首先。详情请参阅我的编辑。 – 2009-12-13 19:40:49