2013-10-21 14 views
11

Modifica: inizialmente pensavo che fosse correlato a .NET Framework 4.5. Ha rivelato che si applica anche a .NET Framework 4.0.Avvia con modifica in Windows Server 2012

C'è un cambiamento nel modo in cui le stringhe vengono gestite in Windows Server 2012 che sto cercando di capire meglio. Sembra che il comportamento di StartsWith sia cambiato. Il problema è riproducibile utilizzando sia .NET Framework 4.0 che 4.5.

Con .NET Framework 4.5 su Windows 7, il programma sottostante stampa "False, t". Su Windows 2012 Server, invece, stampa "True, t".

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     string byteOrderMark = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()); 
     Console.WriteLine("test".StartsWith(byteOrderMark)); 
     Console.WriteLine("test"[0]); 
    } 
} 

In altre parole, StartsWith (ByteOrderMark) restituisce vero indipendentemente dal contenuto della stringa. Se si dispone di codice che tenta di spogliare il segno di ordine di byte utilizzando il seguente metodo, questo codice funziona bene con Windows 7, ma stamperà "est" su Windows 2012.

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
    string byteOrderMark = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()); 
    string someString = "Test"; 

    if (someString.StartsWith(byteOrderMark)) 
     someString = someString.Substring(1); 

    Console.WriteLine("{0}", someString); 
    Console.ReadKey(); 

    } 

}

I renditi conto che hai già fatto qualcosa di sbagliato se hai marcatori di ordini in una stringa, ma ci stiamo integrando con il codice legacy che ha questo. So di poter risolvere questo problema specifico facendo qualcosa di simile in basso, ma voglio capire meglio il problema.

someString = someString.Trim(byteOrderMark[0]); 

Hans Passsant suggerito utilizzando il costruttore di UTF8Encoding che mi permette di dire in modo esplicito per emettere identificatore UTF8. Ho provato questo, ma dà lo stesso risultato. Il codice seguente differisce in output tra Windows 7 e Windows Server 2012. Su Windows 7, stampa "Risultato: Falso". Su Windows Server 2012 viene stampato "Risultato: True".

private static void Main(string[] args) 
    { 
    var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true); 
    string byteOrderMark = encoding.GetString(encoding.GetPreamble()); 
    Console.WriteLine("Result: " + "Hello".StartsWith(byteOrderMark)); 
    Console.ReadKey(); 
    } 

Ho anche provato la seguente variante, che stampa Falso, falso, falso su Windows 7, ma vero, vero, falso su Windows Server 2012, che conferma che è legato alla realizzazione di StartsWith su Windows Server 2012 .

private static void Main(string[] args) 
    { 
    var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true); 
    string byteOrderMark = encoding.GetString(encoding.GetPreamble()); 
    Console.WriteLine("Hello".StartsWith(byteOrderMark)); 
    Console.WriteLine("Hello".StartsWith('\ufeff'.ToString())); 
    Console.WriteLine("Hello"[0] == '\ufeff'); 

    Console.ReadKey(); 
    } 
+0

non avrei nemmeno usare 'trim' - se siete preoccupati solo il primo carattere * * poi basta verificare se' testo [0] == '\ ufeff ''sarebbe abbastanza buono (con una gestione adatta per una stringa vuota). Sembra strano però. –

+0

Certo, funzionerebbe meglio di Trim. Supponiamo che TrimStart funzioni bene. Sto ancora cercando soprattutto di capire perché questo è cambiato in primo luogo. Molte delle risposte sopraelegate su questo sito suggeriscono di verificare prima con StartsWith() e quel codice si romperà quando viene eseguito su Windows Server 2012 con .NET Framework 4.5. Esempio qui: http://stackoverflow.com/questions/1317700/strip-byte-order-mark-from-string-in-c-sharp. – Nitramk

risposta

10

venuto fuori che potevo Repro questo, l'esecuzione del programma di test su Windows 8.1. È nella stessa "famiglia" di Server 2012.

La fonte più probabile del problema è che le regole di confronto sensibili alla cultura sono cambiate. Possono essere, erm, scaglie e possono avere risultati strani su questo tipo di personaggi. Il BOM è uno spazio a larghezza zero. Ragionando per questo richiede lo stesso tipo di ginnastica mentale come capire perché "abc" .StartsWith ("") restituisce true :)

È necessario risolvere il problema utilizzando StringComparison.Ordinal. Questo ha prodotto Falso, falso, falso:

private static void Main(string[] args) { 
    var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true); 
    string byteOrderMark = encoding.GetString(encoding.GetPreamble()); 
    Console.WriteLine("Hello".StartsWith(byteOrderMark, StringComparison.Ordinal)); 
    Console.WriteLine("Hello".StartsWith("\ufeff", StringComparison.Ordinal)); 
    Console.WriteLine("Hello"[0] == '\ufeff'); 
    Console.ReadKey(); 
} 
+0

Si scopre che il problema è riproducibile anche per me con .NET Framework 4.0.Ho aggiornato il mio post principale per includere un nuovo snippet basato sul tuo suggerimento, ma offre un comportamento diverso tra Windows 7 e Windows Server 2012. Ho anche aggiunto uno snippet dove ho hard-code \ ufeff e lo passa a StartsWith e al comportamento visto differisce tra Windows 7 e Windows 2012 Server. Sono d'accordo che questo è strano, ma è quello che sto vedendo. – Nitramk

+0

Fantastico, grazie! Non proprio intuitivo, ma ha un senso. – Nitramk

+0

Ragazzi avete salvato il mio bacon! BTW Sono riuscito a farla franca con 'string byteOrderMarkUtf8 = Encoding.UTF8.GetString (Encoding.UTF8.GetPreamble());' su Windows Server 2012, seguito dal tuo fondamentale 'StartsWith (byteOrderMarkUtf8, StringComparison.Ordinal)'. – snark

Problemi correlati