Come mascherare il carattere di escape - " all'interno di una stringa


Sto affrontando una piccola difficoltà con un Syntax Highlighterche ho creato ed è completo al 90% . Quello che fa è che legge nel testo dall'origine di un file .java, rileva le parole chiave , commenti , etc e scrive un output (colorato) in un file HTML. L'output di esempio da esso è:

Lavoro

(Non ho potuto caricare un'intera pagina html, quindi questo è uno screenshot.) Come, spero, puoi vedere, il mio programma sembra funzionare correttamente con keywords, literals e comments (vedi sotto) e quindi può normalmente documentare quasi tutti i programmi. Ma sembra rompersi quando memorizzo la sequenza di escape per " cioè \" all'interno di un String. Un caso di errore è mostrato di seguito:

Non funziona

L'evidenziazione letterale della stringa non si ferma alla fine del letterale, ma continua fino a trovare un altro spunto, come una parola chiave o un altro letterale.

Quindi, la domanda è come faccio a mascherare / nascondere / rimuovere questo \" dall'interno di un String?

Il metodo stringFilter del mio programma è:

public String stringFilter(String line) {
    if (line == null || line.equals("")) {
        return "";
    }
    StringBuffer buf = new StringBuffer();
    if (line.indexOf("\"") <= -1) {
        return keywordFilter(line);
    }
    int start = 0;
    int startStringIndex = -1;
    int endStringIndex = -1;
    int tempIndex;
    //Keep moving through String characters until we want to stop...
    while ((tempIndex = line.indexOf("\"")) > -1 && !isInsideString(line, tempIndex)) {
        //We found the beginning of a string
        if (startStringIndex == -1) {
            startStringIndex = 0;
            buf.append( stringFilter(line.substring(start,tempIndex)) );
            buf.append("</font>");
            buf.append(literal).append("\"");
            line = line.substring(tempIndex+1);
        }
        //Must be at the end
        else {
            startStringIndex = -1;
            endStringIndex = tempIndex;
            buf.append(line.substring(0,endStringIndex+1));
            buf.append("</font>");
            buf.append(normal);
            line = line.substring(endStringIndex+1);
        }
    }

    buf.append( keywordFilter(line) );

    return buf.toString();
}

MODIFICA

In risposta ai primi commenti e risposte, ecco cosa ho provato:

Un frammento da htmlFilter(String), ma non funziona : (

    //replace '&' i.e. ampersands with HTML escape sequence for ampersand.
    line = line.replaceAll("&", "&amp;");

    //line = line.replaceAll(" ", "&nbsp;");
    line = line.replaceAll("" + (char)35, "&#35;");

    // replace less-than signs which might be confused
    // by HTML as tag angle-brackets;
    line = line.replaceAll("<", "&lt;");
    // replace greater-than signs which might be confused
    // by HTML as tag angle-brackets;
    line = line.replaceAll(">", "&gt;");

    line = multiLineCommentFilter(line);


    //replace the '\\' i.e. escape for backslash with HTML escape sequences.
    //fixes a problem when backslashes preceed quotes.
    //line = line.replaceAll("\\\"", "&#92;&quot;");
    //line = line.replaceAll("" + (char)92 + (char)92, "&#92;&#92;");
    return line;
Author: Astrobleme, 2014-03-09

5 answers

La mia idea è che quando viene soddisfatta una barra rovesciata, ignorare il carattere successivo.

String str = "blah\"blah\\blah\n";

int index = 0;
while (true) {
    // find the beginning
    while (index < str.length() && str.charAt(index) != '\"')
        index++;
    int beginIndex = index;
    if (index == str.length()) // no string found
        break;
    index++;
    // find the ending
    while (index < str.length()) {
        if (str.charAt(index) == '\\') {
            // escape, ignore the next character
            index += 2;
        } else if (str.charAt(index) == '\"') {
            // end of string found
            System.out.println(beginIndex + " " + index);
            break;
        } else {
            // plain content
            index++;
        }
    }
    if (index >= str.length())
        throw new IllegalArgumentException(
                "String literal is not properly closed by a double-quote");
    index++;
}
 1
Author: johnchen902, 2014-03-09 14:10:41

Controlla il carattere trovato in tempIndex-1 è \ quindi non considerare come inizio o fine della stringa.

String originalLine=line;
if ((tempIndex = originalLine.indexOf("\"", tempIndex + 1)) > -1) {
            if (tempIndex==0 || originalLine.charAt(tempIndex - 1) != '\\') { 
...
 1
Author: Braj, 2014-03-09 10:51:41

Passi da seguire:

  • Prima sostituisci tutto \ " con una stringa temporanea come

    String tempStr="forward_slash_followed_by_double_quote";
    line = line.replaceAll("\\\\\"", tempStr);
    //line = line.replaceAll("\\\"", tempStr);
    
  • fai quello che stai facendo
  • Infine sostituisci quella stringa temporanea con \ "

    line = line.replaceAll(tempStr, "\\\\\"");
    //line = line.replaceAll(tempStr, "\\\"");
    
 1
Author: Braj, 2014-03-09 12:09:21

Il problema con la ricerca di una citazione e poi cercando di capire se è sfuggito è che non è sufficiente guardare semplicemente il carattere precedente per vedere se si tratta di una barra rovesciata - considera

String basedir = "C:\\Users\\";

Dove \" non è una citazione con escape, ma è in realtà una barra rovesciata con escape seguita da una citazione senza escape. In generale una citazione preceduta da un dispari numero di barre rovesciate è escape, uno preceduto da un pari numero di barre rovesciate non è.

Un più ragionevole l'approccio sarebbe quello di analizzare attraverso la stringa un carattere alla volta da sinistra a destra piuttosto che cercare di saltare avanti per citare i caratteri. Se non vuoi dover imparare un generatore di parser appropriato come JavaCC o antlr, puoi affrontare questo caso con espressioni regolari usando l'ancora \G (per forzare ogni partita successiva a iniziare alla fine di quella precedente senza spazi vuoti) - se assumiamo che str sia una sottostringa del tuo input che inizia con il carattere dopo l'apertura di str citazione di una stringa letterale quindi

Pattern p = Pattern.compile("\\G(?:\\\\u[0-9A-Fa-f]{4}|\\\\.|[^\"\\\\])");
StringBuilder buf = new StringBuilder();
Matcher m = p.matcher(str);
while(m.find()) buf.append(m.group());

Lascerà buf contenente il contenuto della stringa letterale fino a ma non includendo la citazione di chiusura, e gestirà escape come \", \\ e unicode sfugge \uNNNN.

 1
Author: Ian Roberts, 2014-03-09 14:04:58

Usa la doppia barra " \ \ ""invece di"\""... Forse funziona...

 0
Author: Karsan, 2014-03-09 10:28:51