【问题标题】:C# How to replace Microsoft's Smart Quotes with straight quotation marks?C#如何用直引号替换微软的Smart Quotes?
【发布时间】:2010-09-24 23:49:03
【问题描述】:

我在下面的帖子中询问了弯引号是什么以及为什么我的应用程序无法使用它们,我现在的问题是当我的程序遇到它们时如何替换它们,我如何在 C# 中做到这一点?它们是特殊字符吗?

curly-quotation-marks-vs-square-quotation-marks-what-gives

谢谢

【问题讨论】:

  • 印刷者的引号并不比直引号更真实。

标签: c# smart-quotes


【解决方案1】:

根据 Windows 附带的字符映射应用程序,大括号的 Unicode 值是 0x201c 和 0x201d。用直引号 0x0022 替换这些值,您就可以开始了。

String.Replace(0x201c, '"');
String.Replace(0x201d, '"');

【讨论】:

    【解决方案2】:

    请注意,您所拥有的本质上是一个损坏的 CSV 文件。不加选择地用直引号替换所有印刷者的引号不一定能修复您的文件。就您所知,作为字段值的一部分,一些排版员的引用应该在那里。用直引号替换它们也可能不会为您留下有效的 CSV 文件。

    我认为没有一种算法方法可以修复按照您描述的方式损坏的文件。您最好先花时间调查一下您是如何拥有这些无效文件的,然后再制止它。例如,有人使用 Word 来编辑您的数据文件吗?

    【讨论】:

    • 呃,我不认为这个问题与 CSV 文件有任何关系... :)
    • 否,但 OP 引用的问题确实如此。
    【解决方案3】:

    当我遇到这个问题时,我在 C# 中为 String 类编写了一个扩展方法。

    public static class StringExtensions
    {
        public static string StripIncompatableQuotes(this string s)
        {
            if (!string.IsNullOrEmpty(s))
                return s.Replace('\u2018', '\'').Replace('\u2019', '\'').Replace('\u201c', '\"').Replace('\u201d', '\"');
            else
                return s;
        }
    }
    

    这只是将愚蠢的“智能引号”替换为普通引号。

    [编辑] 已修复,也支持替换“双智能引号”。

    【讨论】:

      【解决方案4】:

      我有一个非常棒的...程序...正是这样做的。您可以撕下脚本并随意使用它。它进行各种替换,位于http://bitbucket.org/nesteruk/typografix

      【讨论】:

        【解决方案5】:

        如果上述方法不起作用,请尝试使用智能单引号:

        string.Replace("\342\200\230", "'")
        string.Replace("\342\200\231", "'")
        

        也可以试试这个智能双引号:

        string.Replace("\342\200\234", '"')
        string.Replace("\342\200\235", '"')
        

        【讨论】:

          【解决方案6】:

          有问题的单词字符的更广泛列表

          if (buffer.IndexOf('\u2013') > -1) buffer = buffer.Replace('\u2013', '-');
          if (buffer.IndexOf('\u2014') > -1) buffer = buffer.Replace('\u2014', '-');
          if (buffer.IndexOf('\u2015') > -1) buffer = buffer.Replace('\u2015', '-');
          if (buffer.IndexOf('\u2017') > -1) buffer = buffer.Replace('\u2017', '_');
          if (buffer.IndexOf('\u2018') > -1) buffer = buffer.Replace('\u2018', '\'');
          if (buffer.IndexOf('\u2019') > -1) buffer = buffer.Replace('\u2019', '\'');
          if (buffer.IndexOf('\u201a') > -1) buffer = buffer.Replace('\u201a', ',');
          if (buffer.IndexOf('\u201b') > -1) buffer = buffer.Replace('\u201b', '\'');
          if (buffer.IndexOf('\u201c') > -1) buffer = buffer.Replace('\u201c', '\"');
          if (buffer.IndexOf('\u201d') > -1) buffer = buffer.Replace('\u201d', '\"');
          if (buffer.IndexOf('\u201e') > -1) buffer = buffer.Replace('\u201e', '\"');
          if (buffer.IndexOf('\u2026') > -1) buffer = buffer.Replace("\u2026", "...");
          if (buffer.IndexOf('\u2032') > -1) buffer = buffer.Replace('\u2032', '\'');
          if (buffer.IndexOf('\u2033') > -1) buffer = buffer.Replace('\u2033', '\"');
          

          【讨论】:

          • 我很好奇,有没有人做过性能测试,显示 .IndexOf() 比在不包含该字符的字符串上运行 .Replace() 便宜?
          • 最便宜的操作是迭代字符串一次,而不是迭代最多 2 * 处理的字符数。例如:foreach(char c in buffer) { /* if char in list to be replaced, replace */ }.
          • 我和 Ted A. 在这里...... buffer.Replace 必须在内部做基本上相当于 buffer.IndexOf 的工作;我无法想象 if-test 和 IndexOf 调用可以改善任何情况。但是,这看起来像是一个很棒的替换列表,所以谢谢!
          • 非常有用的列表,虽然缺少 u201f(双高反 9 引号)。
          【解决方案7】:

          我也有一个程序可以做到这一点,源代码在this fileCP-1252 Fixer 中。它还定义了一些映射,用于在 RTF 字符串中转换字符,同时保留所有格式,这可能对某些人有用。

          它也是所有“智能引号”字符到它们的低ascii对应物、实体代码和字符引用的完整映射。

          【讨论】:

            【解决方案8】:

            @Matthew 所写的 VB 等价物:

            Public Module StringExtensions
            
                <Extension()>
                Public Function StripIncompatableQuotes(BadString As String) As String
                    If Not String.IsNullOrEmpty(BadString) Then
                        Return BadString.Replace(ChrW(&H2018), "'").Replace(ChrW(&H2019), "'").Replace(ChrW(&H201C), """").Replace(ChrW(&H201D), """")
                    Else
                        Return BadString
                    End If
                End Function
            End Module
            

            【讨论】:

              【解决方案9】:

              为了扩展 Nick van Esch 的流行答案,这里是带有 cmets 中字符名称的代码。

              if (buffer.IndexOf('\u2013') > -1) buffer = buffer.Replace('\u2013', '-'); // en dash
              if (buffer.IndexOf('\u2014') > -1) buffer = buffer.Replace('\u2014', '-'); // em dash
              if (buffer.IndexOf('\u2015') > -1) buffer = buffer.Replace('\u2015', '-'); // horizontal bar
              if (buffer.IndexOf('\u2017') > -1) buffer = buffer.Replace('\u2017', '_'); // double low line
              if (buffer.IndexOf('\u2018') > -1) buffer = buffer.Replace('\u2018', '\''); // left single quotation mark
              if (buffer.IndexOf('\u2019') > -1) buffer = buffer.Replace('\u2019', '\''); // right single quotation mark
              if (buffer.IndexOf('\u201a') > -1) buffer = buffer.Replace('\u201a', ','); // single low-9 quotation mark
              if (buffer.IndexOf('\u201b') > -1) buffer = buffer.Replace('\u201b', '\''); // single high-reversed-9 quotation mark
              if (buffer.IndexOf('\u201c') > -1) buffer = buffer.Replace('\u201c', '\"'); // left double quotation mark
              if (buffer.IndexOf('\u201d') > -1) buffer = buffer.Replace('\u201d', '\"'); // right double quotation mark
              if (buffer.IndexOf('\u201e') > -1) buffer = buffer.Replace('\u201e', '\"'); // double low-9 quotation mark
              if (buffer.IndexOf('\u2026') > -1) buffer = buffer.Replace("\u2026", "..."); // horizontal ellipsis
              if (buffer.IndexOf('\u2032') > -1) buffer = buffer.Replace('\u2032', '\''); // prime
              if (buffer.IndexOf('\u2033') > -1) buffer = buffer.Replace('\u2033', '\"'); // double prime
              

              【讨论】:

              • 嗨,芭芭拉。对答案的有用补充,但这更适合作为对现有答案的建议编辑而不是新答案。
              • @Barbara,嗨,没有任何方法可以替换所有字符而无需手动指定每个字符。如果将来代码中除了上面指定的字符之外还有其他字符,那么?
              • 这是我们案例中的当前要求。 MS Word 文件中的任何特殊字符都可以出现,应将其转换为直字符并正确显示。
              【解决方案10】:

              它对我有用,你可以试试下面的代码

              string replacedstring = ("your string with smart quotes").Replace('\u201d', '\'');
              

              谢谢!

              【讨论】:

                【解决方案11】:

                使用 Nick 和 Barbara 的答案,下面是示例代码,其中包含我机器上 1,000,000 次循环的性能统计信息:

                input = "shmB6BhLe0gdGU8OxYykZ21vuxLjBo5I1ZTJjxWfyRTTlqQlgz0yUtPu8iNCCcsx78EPsObiPkCpRT8nqRtvM3Bku1f9nStmigaw";
                input.Replace('\u2013', '-'); // en dash
                input.Replace('\u2014', '-'); // em dash
                input.Replace('\u2015', '-'); // horizontal bar
                input.Replace('\u2017', '_'); // double low line
                input.Replace('\u2018', '\''); // left single quotation mark
                input.Replace('\u2019', '\''); // right single quotation mark
                input.Replace('\u201a', ','); // single low-9 quotation mark
                input.Replace('\u201b', '\''); // single high-reversed-9 quotation mark
                input.Replace('\u201c', '\"'); // left double quotation mark
                input.Replace('\u201d', '\"'); // right double quotation mark
                input.Replace('\u201e', '\"'); // double low-9 quotation mark
                input.Replace("\u2026", "..."); // horizontal ellipsis
                input.Replace('\u2032', '\''); // prime
                input.Replace('\u2033', '\"'); // double prime
                

                时间:958.1011 毫秒

                input = "shmB6BhLe0gdGU8OxYykZ21vuxLjBo5I1ZTJjxWfyRTTlqQlgz0yUtPu8iNCCcsx78EPsObiPkCpRT8nqRtvM3Bku1f9nStmigaw";
                var inputArray = input.ToCharArray();
                for (int i = 0; i < inputArray.Length; i++)
                {
                    switch (inputArray[i])
                    {
                        case '\u2013':
                            inputArray[i] = '-';
                            break;
                        // en dash
                        case '\u2014':
                            inputArray[i] = '-';
                            break;
                        // em dash
                        case '\u2015':
                            inputArray[i] = '-';
                            break;
                        // horizontal bar
                        case '\u2017':
                            inputArray[i] = '_';
                            break;
                        // double low line
                        case '\u2018':
                            inputArray[i] = '\'';
                            break;
                        // left single quotation mark
                        case '\u2019':
                            inputArray[i] = '\'';
                            break;
                        // right single quotation mark
                        case '\u201a':
                            inputArray[i] = ',';
                            break;
                        // single low-9 quotation mark
                        case '\u201b':
                            inputArray[i] = '\'';
                            break;
                        // single high-reversed-9 quotation mark
                        case '\u201c':
                            inputArray[i] = '\"';
                            break;
                        // left double quotation mark
                        case '\u201d':
                            inputArray[i] = '\"';
                            break;
                        // right double quotation mark
                        case '\u201e':
                            inputArray[i] = '\"';
                            break;
                        // double low-9 quotation mark
                        case '\u2026':
                            inputArray[i] = '.';
                            break;
                        // horizontal ellipsis
                        case '\u2032':
                            inputArray[i] = '\'';
                            break;
                        // prime
                        case '\u2033':
                            inputArray[i] = '\"';
                            break;
                        // double prime
                    }
                }
                input = new string(inputArray);
                

                时间:362.0858 毫秒

                【讨论】:

                • 很有趣,但这是一个非常短的字符串。尝试随机的 10-char、100-char、1000-char 和 10,000-char 字符串会更有趣。这将使您对改进的顺序有所了解。不过,我知道这是旧的 ;-)
                【解决方案12】:

                只是插话,我用 Regex replace 完成了这个,只是为了根据我要替换它们的内容一次处理几个:

                        public static string ReplaceWordChars(this string text)
                        {
                            var s = text;
                            // smart single quotes and apostrophe,  single low-9 quotation mark, single high-reversed-9 quotation mark, prime
                            s = Regex.Replace(s, "[\u2018\u2019\u201A\u201B\u2032]", "'");
                            // smart double quotes, double prime
                            s = Regex.Replace(s, "[\u201C\u201D\u201E\u2033]", "\"");
                            // ellipsis
                            s = Regex.Replace(s, "\u2026", "...");
                            // em dashes
                            s = Regex.Replace(s, "[\u2013\u2014]", "-");
                            // horizontal bar
                            s = Regex.Replace(s, "\u2015", "-");
                            // double low line
                            s = Regex.Replace(s, "\u2017", "-");
                            // circumflex
                            s = Regex.Replace(s, "\u02C6", "^");
                            // open angle bracket
                            s = Regex.Replace(s, "\u2039", "<");
                            // close angle bracket
                            s = Regex.Replace(s, "\u203A", ">");
                            // weird tilde and nonblocking space
                            s = Regex.Replace(s, "[\u02DC\u00A0]", " ");
                            // half
                            s = Regex.Replace(s, "[\u00BD]", "1/2");
                            // quarter
                            s = Regex.Replace(s, "[\u00BC]", "1/4");
                            // dot
                            s = Regex.Replace(s, "[\u2022]", "*");
                            // degrees 
                            s = Regex.Replace(s, "[\u00B0]", " degrees");
                
                            return s;
                        }
                

                那里还有一些替代品。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2021-02-17
                  • 1970-01-01
                  • 2011-05-09
                  • 1970-01-01
                  • 2013-04-18
                  • 2011-02-06
                  • 2011-01-26
                  相关资源
                  最近更新 更多