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 è:
(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:
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("&", "&");
//line = line.replaceAll(" ", " ");
line = line.replaceAll("" + (char)35, "#");
// replace less-than signs which might be confused
// by HTML as tag angle-brackets;
line = line.replaceAll("<", "<");
// replace greater-than signs which might be confused
// by HTML as tag angle-brackets;
line = line.replaceAll(">", ">");
line = multiLineCommentFilter(line);
//replace the '\\' i.e. escape for backslash with HTML escape sequences.
//fixes a problem when backslashes preceed quotes.
//line = line.replaceAll("\\\"", "\"");
//line = line.replaceAll("" + (char)92 + (char)92, "\\");
return line;
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++;
}
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) != '\\') {
...
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, "\\\"");
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
.
Usa la doppia barra " \ \ ""invece di"\""... Forse funziona...