Como mudar a minha regex para correspondência / substituir em 2ª, 3ª, ... palavras, mas não no primeiro?

Vanua Aunav:

A tarefa deve ser resolvido usando expressões regulares sem o uso de classes container.

Entrada: texto (pode consistir em letras latinas e cirílicas, não contém _)

Saída: texto de origem, mas preceder todas as palavras repetidas com um sublinhado _

Para considerar uma palavra como uma sequência contendo apenas letras (todos os outros personagens não estão incluídos na palavra). Criar um método de conversão estática que converte entrada para a saída.

Método para completa:

public static String convert (String input) {
    ...
}

exemplo de entrada:

This is a test
And this is also a test
And these are also tests
test
Это тест
Это также тест
И это также тесты

exemplo de saída:

This _is _a _test
_And this _is _also _a _test
_And these are _also tests
_test
_Это _тест
_Это _также _тест
И это _также тесты

Minha tentativa:

public static void convert(String input) {
        Pattern p = Pattern.compile("(\\b\\w+\\b)(?=[\\s\\S]*\\b\\1\\b[\\s\\S]*\\b\\1\\b)", Pattern.UNICODE_CHARACTER_CLASS);
        String res = p.matcher(input+" "+input).replaceAll("_$1");
        res = res.substring(0, res.length() - 1 - p.matcher(input).replaceAll("_$1").length());
        System.out.println(res);
    }

Minha saída: digite descrição da imagem aqui

This _is _a _test
_And this _is _also _a test
_And these are _also tests
_test
_Это _тест
_Это _также _тест
И это _также тесты

Palavra "teste" na segunda linha, sem "_" Mas eu preciso "_test"

Wiktor Stribiżav:

Você pode coletar todas as palavras repetidas e, em seguida, prefixar-los com _:

// Java 9+
String s = "This is a test\nAnd this is also a test\nAnd these are also tests\ntest\nЭто тест\nЭто также тест\nИ это также тесты";
String rx = "(?sU)\\b(\\w+)\\b(?=.*\\b\\1\\b)";
String[] results = Pattern.compile(rx).matcher(s).results().map(MatchResult::group).toArray(String[]::new);
System.out.println(s.replaceAll("(?U)\\b(?:" + String.join("|", results) + ")\\b", "_$0"));

// Java 8
String s = "This is a test\nAnd this is also a test\nAnd these are also tests\ntest\nЭто тест\nЭто также тест\nИ это также тесты";
String rx = "(?sU)\\b(\\w+)\\b(?=.*\\b\\1\\b)";
List<String> matches = new ArrayList<>();
Matcher m = Pattern.compile(rx).matcher(s);
while (m.find()) {
    matches.add(m.group());
}
System.out.println(s.replaceAll("(?U)\\b(?:" + String.join("|", matches) + ")\\b", "_$0"));

Veja o Java demonstração online eo segundo trecho de demonstração . Resultado:

This _is _a _test
_And this _is _also a _test
And these are _also tests
test
_Это _тест
_Это _также тест
И это _также тесты

Nota I substituído [\s\S]construção solução com o .combinado com a sopção de sinalizador dotall incorporado (de modo que .poderia coincidir com quebras de linha, também), usado Java 9+ .results()método para retornar todos os jogos e construiu o padrão final para fora das correspondências encontradas unidas com |operador OR alternância.

detalhes

  • (?sU)\b(\w+)\b(?=.*\b\1\b):
    • (?sU)- um dotall incorporado (marcas .coincidir com quebras de linha, também) e UNICODE_CHARACTER_CLASS (faz todos os atalhos Unicode ciente) opções bandeira
    • \b - limite de palavra
    • (\w+)- Grupo 1: 1+ caracteres de palavra, letras, números ou _s
    • \b - limite de palavra
    • (?=.*\b\1\b) - imediatamente à direita, deve haver nenhum 0+ caracteres, o máximo possível, seguiu com o mesmo valor que no Grupo 1 como uma palavra inteira.
  • (?U)\\b(?:" + String.join("|", results) + ")\\b": Este padrão será semelhante (?U)\b(?:test|is|Это|тест|также)\b
    • (?U) - uma opção embutida bandeira UNICODE_CHARACTER_CLASS
    • \b - limite de palavra
    • (?:test|is|Это|тест|также) - um grupo de alternância não-captura
    • \b - limite de palavra

A substituição é _$0para o segundo regex como o _é anexado a todo o valor de partida, $0.

Acho que você gosta

Origin http://43.154.161.224:23101/article/api/json?id=313170&siteId=1
Recomendado
Clasificación