【问题标题】:.NET method to convert a string to sentence case.NET 方法将字符串转换为句子大小写
【发布时间】:2010-06-29 14:04:44
【问题描述】:

我正在寻找一个函数来将大写的文本字符串转换为 SentenceCase。我能找到的所有示例都将文本转换为 TitleCase。

一般意义上的句格 描述大写的方式 在句子中使用。句子 案例还描述了标准 英文句子的大写, 即句子的第一个字母 大写,其余为 小写(除非要求 出于特定原因大写, 例如专有名词、首字母缩写词等)。

谁能指出 SentenceCase 的脚本或函数的方向?

【问题讨论】:

标签: c# string sentencecase


【解决方案1】:

.NET 中没有内置任何东西 - 但是,这是正则表达式处理实际上可能运行良好的情况之一。我首先将整个字符串转换为小写,然后,作为第一个近似值,您可以使用正则表达式查找所有序列,如[a-z]\.\s+(.),并使用ToUpper() 将捕获的组转换为大写。 RegEx 类有一个重载的 Replace() 方法,该方法接受 MatchEvaluator 委托,允许您定义如何替换匹配的值。

这是一个工作中的代码示例:

var sourcestring = "THIS IS A GROUP. OF CAPITALIZED. LETTERS.";
// start by converting entire string to lower case
var lowerCase = sourcestring.ToLower();
// matches the first sentence of a string, as well as subsequent sentences
var r = new Regex(@"(^[a-z])|\.\s+(.)", RegexOptions.ExplicitCapture);
// MatchEvaluator delegate defines replacement of setence starts to uppercase
var result = r.Replace(lowerCase, s => s.Value.ToUpper());

// result is: "This is a group. Of uncapitalized. Letters."

这可以通过多种不同的方式进行改进,以更好地匹配更广泛的句型(不仅仅是那些以字母+句号结尾的句型)。

【讨论】:

  • 我为此做了一个扩展方法,并在更改字符串之前添加了一个可选的布尔变量来可选地小写字符串。这将有助于字符串,例如下面杰伊的回答中的字符串。可以理解,这是我很少使用的东西,但我可以看到它在某些时候会派上用场。
【解决方案2】:

这对我有用。

/// <summary>
/// Converts a string to sentence case.
/// </summary>
/// <param name="input">The string to convert.</param>
/// <returns>A string</returns>
public static string SentenceCase(string input)
{
    if (input.Length < 1)
        return input;

    string sentence = input.ToLower();
    return sentence[0].ToString().ToUpper() +
       sentence.Substring(1);
}

【讨论】:

  • 如果输入是多个句子,您还需要使用点作为分隔符来分割每个句子。
  • “点作为分隔符”并没有真正削减它。 Mr. and Mrs. Smith have $1,000.00 each; they live on Magnolia Blvd. in the blue house.
  • 它也没有考虑大写中提到的其他原因:(除非出于特定原因需要大写,例如专有名词、首字母缩略词等)。
  • 是的,这是一种简单的方法……无论如何,很少需要使用它。这不是您在内容管理中使用的东西。
【解决方案3】:
public string GetSentenceCase(string ReqdString) {
    string StrInSentCase = "";
    for (int j = 0; j < ReqdString.Length; j++) {
        if (j == 0) {
           StrInSentCase = ReqdString.ToString().Substring(j, 1).ToUpper();
        }
        else {
            StrInSentCase = StrInSentCase + ReqdString.ToString().Substring(j, 1).ToLower();
        }
    }
    return StrInSentCase.ToString();
}

【讨论】:

    【解决方案4】:

    如果你想判断一个包含标点符号的字符串,而不仅仅是句点:

    string input = "THIS IS YELLING! WHY ARE WE YELLING? BECAUSE WE CAN. THAT IS ALL.";
    var sentenceRegex = new Regex(@"(^[a-z])|[?!.:,;]\s+(.)", RegexOptions.ExplicitCapture);
    input = sentenceRegex.Replace(input.ToLower(), s => s.Value.ToUpper());
    

    【讨论】:

      【解决方案5】:

      F# 中的解决方案:

      open System
      
      let proper (x : string) =
          x.Split(' ')
          |> Array.filter ((<>) "")
          |> Array.map (fun t ->
              let head = Seq.head t |> Char.ToUpper |> string
              let tail = Seq.tail t |> Seq.map (Char.ToLower >> string)
              Seq.append [head] tail
              |> Seq.reduce (fun acc elem -> acc + elem))
          |> Array.reduce (fun acc elem -> acc + " " + elem)
      

      【讨论】:

        【解决方案6】:

        有一个内置的ToTitleCase() 功能,将来会扩展以支持多种文化。

        来自 MSDN 的示例:

        using System;
        using System.Globalization;
        
        public class Example
        {
           public static void Main()
           {
              string[] values = { "a tale of two cities", "gROWL to the rescue",
                                  "inside the US government", "sports and MLB baseball",
                                  "The Return of Sherlock Holmes", "UNICEF and children"};
        
              TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
              foreach (var value in values)
                 Console.WriteLine("{0} --> {1}", value, ti.ToTitleCase(value));
           }
        }
        // The example displays the following output:
        //    a tale of two cities --> A Tale Of Two Cities
        //    gROWL to the rescue --> Growl To The Rescue
        //    inside the US government --> Inside The US Government
        //    sports and MLB baseball --> Sports And MLB Baseball
        //    The Return of Sherlock Holmes --> The Return Of Sherlock Holmes
        //    UNICEF and children --> UNICEF And Children
        

        虽然它通常很有用,但它有一些重要的限制:

        通常,标题大小写将单词的第一个字符转换为 大写,其余字符为小写。然而,这 方法当前不提供适当的大小写来转换一个单词 完全大写,例如首字母缩略词。下表显示 该方法呈现多个字符串的方式。

        ...ToTitleCase 方法提供任意大小写行为 这不一定在语言上是正确的。语言上的 正确的解决方案需要额外的规则,而当前 算法更简单,更快。我们保留制作的权利 以后这个 API 会变慢。

        来源:http://msdn.microsoft.com/en-us/library/system.globalization.textinfo.totitlecase.aspx

        【讨论】:

        • 但是title case和sentence case不一样
        【解决方案7】:

        如果你输入的字符串不是一个句子,而是很多个句子,这将成为一个非常棘手的问题。

        正则表达式将被证明是一种非常宝贵的工具,但是 (1) 您必须非常了解它们才能有效,并且 (2) 它们可能无法完全靠自己完成这项工作。

        考虑这句话

        “谁在 1 号,”史密斯先生——他没有笑——回答道。

        这句话不是以字母开头,它有一个数字,各种标点符号,一个专有名称,中间有一个.

        错综复杂,就这么一句话。

        使用 RegEx 时最重要的事情之一就是“了解您的数据”。如果您知道要处理的句子类型的广度,您的任务将更易于管理。

        在任何情况下,您都必须玩弄您的实施,直到您对结果感到满意为止。我建议使用一些示例输入编写一些自动化测试——当你在你的实现上工作时,你可以定期运行测试来看看你在哪里接近了,你仍然没有达到目标。

        【讨论】:

          【解决方案8】:

          这就是我使用的 (VB.NET)。它适用于大多数情况,包括:

          • 多句
          • 以空格开头和结尾的句子
          • 以 A-Z 以外的字符开头的句子。例如,它适用于:“如果你想要 100.00 美元,那就问我吧”。

            <Extension()>
            Public Function ToSentanceCase(ByVal s As String) As String
                ' Written by Jason. Inspired from: http://www.access-programmers.co.uk/forums/showthread.php?t=147680
            
                Dim SplitSentence() As String = s.Split(".")
            
                For i = 0 To SplitSentence.Count - 1
                    Dim st = SplitSentence(i)
            
                    If st.Trim = "" Or st.Trim.Count = 1 Then Continue For ' ignore empty sentences or sentences with only 1 character.
            
                    ' skip past characters that are not A-Z, 0-9 (ASCII) at start of sentence.
                    Dim y As Integer = 1
                    Do Until y > st.Count
                        If (Asc(Mid(st, y, 1)) >= 65 And Asc(Mid(st, y, 1)) <= 90) Or _
                              (Asc(Mid(st, y, 1)) >= 97 And Asc(Mid(st, y, 1)) <= 122) Or _
                             (Asc(Mid(st, y, 1)) >= 48 And Asc(Mid(st, y, 1)) <= 57) Then
                            GoTo Process
                        Else
                            Dim w = Asc(Mid(st, y, 1))
                            y += 1
                        End If
                    Loop
                    Continue For
            
            Process:
                    Dim sStart As String = ""
                    If y > 1 Then sStart = Left(st, 0 + (y - 1))
            
                    Dim sMid As String = UCase(st(y - 1)) ' capitalise the first non-space character in sentence.
            
                    Dim sEnd As String = Mid(st, y + 1, st.Length)
            
                    SplitSentence(i) = sStart & sMid & sEnd
            
                Next
            
                ' rejoin sentances back together:
                Dim concat As String = ""
                For Each st As String In SplitSentence
                    concat &= st & "."
                Next
            
                concat = concat.TrimEnd(1)
            
                Return concat
            
            End Function
            

          但至于专有名词和首字母缩略词,嗯……在英语中总会出现标点符号不那么简单的情况。例如,此脚本不会检测到省略号(“...”)或缩写(例如:“琼斯先生住在 Chris 家附近的 Magnolia Blvd”)。

          要彻底解决这个问题,您需要制作一本包含该语言所有可能的缩写/标点符号的字典,并保持字典是最新的!考虑到这一点后,大多数人都会对折衷感到满意,否则就使用 Microsoft Word。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-10-29
            • 1970-01-01
            • 2010-11-15
            • 1970-01-01
            相关资源
            最近更新 更多