2
votes

Quelle est la meilleure façon de remplacer tous les caractères spéciaux par leurs noms complets dans une chaîne Java?

Je souhaite convertir tous les caractères spéciaux d'une chaîne en leurs noms complets.

Exemple:

Entrée: Qu'est-ce que le débordement de pile?

Sortie: Qu'est-ce que le point d'interrogation de débordement de pile

J'ai utilisé replaceall() pour le faire, mais y a-t-il un moyen plus simple de le faire car je dois écrire une ligne pour chaque caractère spécial?

text = text.replaceAll("\\.", " Fullstop ");
text = text.replaceAll("!", " Exclamation mark ");
text = text.replaceAll("\"", " Double quote ");
text = text.replaceAll("#", " Hashtag ");
...


0 commentaires

5 Réponses :


1
votes

Une approche ici serait de maintenir un hashmap contenant tous les symboles et leurs noms de remplacement. Ensuite, effectuez une itération regex sur la chaîne d'entrée et effectuez tous les remplacements.

input:  The quick! brown #fox "jumps" over the lazy dog.
output: The quick Exclamation mark  brown  Hashtag fox  Double quote jumps Double quote  over the lazy dog Fullstop 

Cela imprime:

Map<String, String> terms = new HashMap<>();
terms.put(".", " Fullstop ");
terms.put("!", " Exclamation mark ");
terms.put("\"", " Double quote ");
terms.put("#", " Hashtag ");

String input = "The quick! brown #fox \"jumps\" over the lazy dog.";
Pattern pattern = Pattern.compile("[.!\"#]");
Matcher matcher = pattern.matcher(input);
StringBuffer buffer = new StringBuffer();
while (matcher.find()) {
    matcher.appendReplacement(buffer, terms.get(matcher.group(0)));
}
matcher.appendTail(buffer);

System.out.println("input:  " + input);
System.out.println("output: " + buffer.toString());

L'approche ci - dessus semble un peu bavard, mais en pratique toute la logique de remplacement de base se produit dans une ligne d'un while boucle. Si vous êtes sur Java 8, vous pouvez également utiliser une approche de flux Matcher , mais la logique serait plus ou moins la même.


0 commentaires

0
votes

Vous pouvez utiliser Stream :

String text= "Input: What is stack overflow?";
HashMap<String, String> map = new HashMap<String, String>(){{
    put("\\.", " Fullstop ");
    put("!", " Exclamation mark ");
    put("\"", " Double quote ");
    put("#", " Hashtag ");
    put("?", " question mark");
}};
System.out.println(
        Stream.of(text.split(""))
                .map(s -> map.getOrDefault(s,s))
                .collect(Collectors.joining())
);


0 commentaires

1
votes

Regardez les noms Unicode intégrés:

    String s = "a!\".";
    s.codePoints()
            .filter(cp -> !Character.isAlphabetic(cp))
            .forEach(cp -> System.out.println(Character.getName(cp)));

EXCLAMATION MARK
QUOTATION MARK
FULL STOP

Avec un toLowerCase / capitalize, vous pouvez obtenir un résultat fin et compact.


0 commentaires

0
votes

l'utilisation d'un IntStream permet de le faire d'un seul coup

System.out.println(
    text.codePoints().collect( StringWriter::new,
        (w, c) -> w.write( Character.isAlphabetic( c )
            ? Character.toString( c ) : '‹' + Character.getName( c ) + '›'),
        ( w1, w2 ) -> w1.write( w2.toString() ) ).toString() );

â € ¦ou adapté avec l'idée de Joop Eggen (mais en gardant le texte original)

String text= "Input: What is stack overflow?";
System.out.println(
    text.codePoints().mapToObj( c -> {
      switch( c ) {
      case '.':
        return "‹Fullstop›";
      case '!':
        return "‹Exclamation mark›";
      case '"':
        return "‹Double quote›";
      case '#':
        return "‹Hashtag›";
      case '?':
        return "‹Question mark›";
      default:
        return String.valueOf( (char)c );
      }
    } ).collect( StringWriter::new, StringWriter::write,
        ( w1, w2 ) -> w1.write( w2.toString() ) ).toString() );

obtient: Input‹COLON›‹SPACE›What‹SPACE›is‹SPACE›stack‹SPACE›overflow‹QUESTION MARK›


0 commentaires

0
votes

Vous pouvez le faire en une seule déclaration.

Vous pouvez chaîner les opérations de chaîne, c'est-à-dire que le résultat d'une opération de chaîne peut être passé à l'opération suivante en chaînant comme indiqué ci-dessous:

He asked,  Double quote What is Stackoverflow? Double quote 
How beautiful Exclamation mark 
Neither am I the God nor am I the Devil Fullstop 

Production:

public class Main {
    public static void main(String[] args) {
        String text = "He asked, \"What is Stackoverflow?\"\nHow beautiful!\nNeither am I the God nor am I the Devil.";
        
        text = text.replaceAll("\\.", " Fullstop ")
                .replaceAll("!", " Exclamation mark ")
                .replaceAll("\"", " Double quote ")
                .replaceAll("#", " Hashtag ");
        
        System.out.println(text);
    }
}


4 commentaires

Cette approche présente l'inconvénient que vous devez itérer toute la chaîne d'entrée une fois, pour chaque symbole à remplacer, afin qu'elle ne soit pas trop bien mise à l'échelle.


@TimBiegeleisen - Je ne comprends pas comment vous pouvez éviter d'itérer toute la chaîne pour qu'un symbole soit remplacé, par exemple si vous avez remplacé le point dans toute la chaîne, vous devez à nouveau remplacer le point d'exclamation dans la chaîne entière. N'est-ce pas? Même dans votre solution, matcher.find() analyse toute la chaîne. S'il vous plaît laissez-moi savoir si ce n'est pas correct.


Ma solution itère la chaîne d'entrée une fois , tandis que dans votre solution, chaque appel à replaceAll analysera l'entrée une fois.


@TimBiegeleisen - Mon commentaire était basé sur ma compréhension que while (matcher.find()) { System.out.println("Hello"); matcher.appendReplacement(buffer, terms.get(matcher.group(0))); } affichera Hello cinq fois car while (matcher.find()) 5 fois. J'analyserai votre réponse et commenterai à nouveau quand j'aurai le temps. Merci pour vos commentaires.