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"
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 s
opçã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 é _$0
para o segundo regex como o _
é anexado a todo o valor de partida, $0
.