首页 > 解决方案 > 正则表达式 - 无法将西里尔字符与 \w 匹配

问题描述

任务:

该任务必须使用正则表达式而不使用容器类来解决。

输入:文本(可能由拉丁文和西里尔文组成)。输出:源文本,但每个单词的第一个字符(由三个或更多字符组成)的大小写必须反转。

将单词视为仅包含字母的序列(单词中不包含所有其他字符)。创建一个将输入转换为输出的静态转换方法。

示例输入数据

When I was younger
I never needed
Прощай, со всех вокзалов поезда
уходят в Дальние Края

示例输出

when I Was Younger
I Never Needed
прощай, со Всех Вокзалов Поезда
Уходят в дальние края

我的尝试:

public static String convert(String input) {
    StringBuilder sb = new StringBuilder(input);
    Pattern p = Pattern.compile("[\\W&&[\\d]]?[\\w&&[\\D]]+");
    Matcher m = p.matcher(input);
    while (m.find()) {
        if (m.group().length() >= 3) {
            if (Character.isUpperCase(sb.charAt(m.start()))) {
                sb.setCharAt(m.start(), Character.toLowerCase(sb.charAt(m.start())));
            } else {
                sb.setCharAt(m.start(), Character.toUpperCase(sb.charAt(m.start())));
            }

        }
    }
    return sb.toString();
}

我需要输出:

when I Was Younger
I Never Needed
прощай, со Всех Вокзалов Поезда
Уходят в дальние края

但是我有:

when I Was Younger
I Never Needed
Прощай, со всех вокзалов поезда
уходят в Дальние Края

标签: javaregex

解决方案


调试问题

\w不匹配西里尔字符。我通过在您的 while 循环中打印匹配的组来解决这个问题:

System.out.println(m.group());

打印:


我 年轻的时候
, 我 从来 不需要



其他词没有一个匹配。

解决方案 1

要匹配西里尔字符,您可以使用\p{L}. 如果您使用{3}匹配三个字符,则可以避免在循环中进行长度检查。\b匹配边界字符。把它们放在一起:

public static String convert(String input) {
    StringBuilder sb = new StringBuilder(input);
    Pattern p = Pattern.compile("\\b\\p{L}{3}");
    Matcher m = p.matcher(input);
    while (m.find()) {
        char firstChar = sb.charAt(m.start());
        if (Character.isUpperCase(firstChar)) {
            sb.setCharAt(m.start(), Character.toLowerCase(firstChar));
        } else {
            sb.setCharAt(m.start(), Character.toUpperCase(firstChar));
        }
    }
    return sb.toString();
}

产生:

当我 年轻时
我从来不需要
прощай, со Всех Вокзалов Поезда
Уходят в дальние края

解决方案 2

或者,如果你想要真正的嗖嗖声,请使用正向前瞻(非捕获组)和replaceAll采用 lambda 的 matcher 方法:

public static String convert(String input) {
    Pattern p = Pattern.compile("\\b(\\p{L})(?=\\p{L}{2})");
    Matcher m = p.matcher(input);
    return m.replaceAll(match -> {
        char ch = match.group().charAt(0);
        if (Character.isUpperCase(ch)) {
            return "" + Character.toLowerCase(ch);
        }
        return "" + Character.toUpperCase(ch);
    });
}

还产生:

当我 年轻时
我从来不需要
прощай, со Всех Вокзалов Поезда
Уходят в дальние края


推荐阅读