使用 Java 和 RegEx 转换字符串中的大小写

Posted

技术标签:

【中文标题】使用 Java 和 RegEx 转换字符串中的大小写【英文标题】:Use Java and RegEx to convert casing in a string 【发布时间】:2011-02-15 18:59:00 【问题描述】:

问题:转弯

"My Testtext TARGETSTRING My Testtext" 

进入

"My Testtext targetstring My Testtext"

Perl 支持可以在替换字符串中使用的“\L”操作。

Pattern-Class 不支持此操作:

此类不支持的 Perl 构造: [...] 预处理操作\l、\u、\L和\U。 https://docs.oracle.com/javase/10/docs/api/java/util/regex/Pattern.html

【问题讨论】:

我不明白。 "my testtext TARGETSTRING my testtext".toLowerCase(); 怎么了? 对不起,这个例子很糟糕。 toLowerCase 不适用于“My Testtext TARGETSTRING My Testtext” 【参考方案1】:

Java9+

从 Java 9+ 开始,您可以使用 Matcher::replaceAll,您可以使用 Function<MatchResult, String>,例如我们使用 polygenelubricants 的示例:

String text = "this is just a test which upper all short words";
String regex = "\\b\\w0,3\\b";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(text);
String result = matcher.replaceAll(matche -> matche.group().toUpperCase());

System.out.println(result);

或者只是:

String result = Pattern.compile(regex)
        .matcher(text)
        .replaceAll(matche -> matche.group().toUpperCase());

输出

this IS just A test which upper ALL short words
     ^^      ^                  ^^^

【讨论】:

【参考方案2】:

Java 8”中的这个转换函数怎么样

/**
 * Searches the given pattern in the given src string and applies the txr to the
 * matches
 * 
 * @param src     The string to be converted
 * @param pattern the pattern for which the transformers to be applied.
 * @param txr     The transformers for the mathed patterns.
 * @return The result after applying the transformation.
 */
private static String fromTo(String src, String pattern, Function<String, String> txr) 
    Matcher m = Pattern.compile(pattern).matcher(src);

    StringBuilder sb = new StringBuilder();
    int last = 0;

    while (m.find()) 
        sb.append(src.substring(last, m.start()));
        sb.append(txr.apply(m.group(0)));
        last = m.end();
    
    sb.append(src.substring(last));
    return sb.toString();

【讨论】:

【参考方案3】:

要在正则表达式级别上执行此操作,您必须使用\U 来打开大写模式并使用\E 来关闭它。以下是如何在 IntelliJ IDEA find-and-replace 对话框中使用此功能的示例,该对话框将类字段集转换为 JUnit 断言(在 IDE 工具提示中是 find-and-replace 转换的结果):

【讨论】:

这是 IntelliJ 特有的,普通的 Java 正则表达式不支持。 还有\L 用于小写模式(也以\E 结尾)。当然,这也是 IntelliJ 特有的。 @ddekany 从技术上讲,你是对的:JDK 库不支持它(docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html 参见“与 Perl 5 的比较”),但我猜 IntelliJ IDEA 使用了一些独立的正则表达式库。【参考方案4】:

您不能在 Java 正则表达式中执行此操作。您必须使用 String.toUpperCase()toLowerCase() 手动进行后期处理。

这是一个示例,说明如何使用正则表达式查找句子中长度至少为 3 的单词并将其大写

    String text = "no way oh my god it cannot be";
    Matcher m = Pattern.compile("\\b\\w3,\\b").matcher(text);

    StringBuilder sb = new StringBuilder();
    int last = 0;
    while (m.find()) 
        sb.append(text.substring(last, m.start()));
        sb.append(m.group(0).toUpperCase());
        last = m.end();
    
    sb.append(text.substring(last));

    System.out.println(sb.toString());
    // prints "no WAY oh my GOD it CANNOT be"

注意appendReplacementappendTail

请注意,上述解决方案使用substring并管理tail索引等。实际上,如果您使用Matcher.appendReplacementappendTail,则可以不使用这些。

    StringBuffer sb = new StringBuffer();
    while (m.find()) 
        m.appendReplacement(sb, m.group().toUpperCase());
    
    m.appendTail(sb);

注意sb 现在是StringBuffer 而不是StringBuilder。在Matcher 提供StringBuilder 重载之前,如果您想使用这些方法,则只能使用较慢的StringBuffer

是否值得以较低的效率换取较高的可读性,这取决于您。

另见

StringBuilder and StringBuffer in Java

【讨论】:

从 Java 9 开始,Matcher.appendReplacement 对 StringBuilder 有一个重载【参考方案5】:

您可以使用regexp capturing group(如果您真的需要使用正则表达式,也就是说,如果“TARGETSTRING”足够复杂并且足够“常规”以证明被正则表达式检测到是合理的)。 然后将toLowerCase() 应用到组#1。

import java.util.regex.*;

public class TargetToLowerCase 

  public static void main(String[] args) 
    StringBuilder sb= new StringBuilder(
            "my testtext TARGETSTRING my testtext");
    System.out.println(sb);
    String regex= "TARGETSTRING ";
    Pattern p = Pattern.compile(regex); // Create the pattern.
    Matcher matcher = p.matcher(sb); // Create the matcher.
    while (matcher.find()) 
      String buf= sb.substring(matcher.start(), matcher.end()).toLowerCase();
      sb.replace(matcher.start(), matcher.end(), buf);
    
    System.out.println(sb);
  

【讨论】:

这应该是伪代码吗? "$1".toLowerCase() 显然首先计算,所以 replaceAll 只看到 "$1",这意味着它什么也不做。 @Matthew:对,实际的基于正则表达式的解决方案要复杂一些。我已经修改了答案以反映它。 NICE 技巧使用sb.replace 来利用替换总是(?)与原始字符串长度相同的事实。否则这是行不通的。非常好! 不幸的是,大小写切换不会保留字符串长度。请参阅:Does Java's toLowerCase() preserve original string length?。

以上是关于使用 Java 和 RegEx 转换字符串中的大小写的主要内容,如果未能解决你的问题,请参考以下文章

java大小写转换

如何使用 Java Regex 查找字符串中的所有重复字符序列?

在 Rails 中将文件大小字符串转换为等效千字节

java中字符串中的大小写转换

RegEx - 正向后视中的可选子字符串

强制转换过程中的 Oracle RegEx