Der beste Weg, um Pascal Case in einen Satz umzuwandeln

75

Was ist der beste Weg, um von Pascal Case (Upper Camel Case) in einen Satz umzuwandeln?

Zum Beispiel beginnend mit

"AwaitingFeedback"

und das umwandeln in

"Awaiting feedback"

C # vorzuziehen, aber ich könnte es von Java oder ähnlichem konvertieren.

Garry Shutler
quelle
2
Kamel Fall wartet auf Rückmeldung und nicht auf Rückmeldung (Pascal Fall). Auch was Sie tun möchten, ist nicht vollständig möglich. Wie wäre es mit disableGPS? Gibt es eine Lösung, die allgemein genug ist, um diese Fälle zu behandeln?
kgiannakakis
@kgiannakakis hat die Frage entsprechend geändert. Ich vergesse immer, wie die Namen aussehen, besonders wenn es ein oberes und ein unteres Kamelgehäuse gibt.
Garry Shutler

Antworten:

71
public static string ToSentenceCase(this string str)
{
    return Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1]));
}

In Versionen von Visual Studio nach 2015 können Sie dies tun

public static string ToSentenceCase(this string str)
{
    return Regex.Replace(str, "[a-z][A-Z]", m => $"{m.Value[0]} {char.ToLower(m.Value[1])}");
}

Basierend auf: Konvertieren des Pascal-Falls in Sätze mit regulären Ausdrücken

RoadieRich
quelle
16

Das funktioniert bei mir:

Regex.Replace(strIn, "([A-Z]{1,2}|[0-9]+)", " $1").TrimStart()
SSTA
quelle
5
Wie ändert sich der Fall des Buchstabens nach dem Leerzeichen?
Drew Noakes
1
Dies gibt möglicherweise nicht zurück, was Sie für Fälle wie AwaitingTFeedbackoder beabsichtigen Awaiting9Feedback. Jef Antwort ist besser für mich (die Renditen Awaiting T Feedbackund Awaiting9 Feedbackrespectively).
Nawfal
16

Ich werde es vorziehen, Humanizer dafür zu verwenden. Humanizer ist eine tragbare Klassenbibliothek, die alle Ihre .NET-Anforderungen zum Bearbeiten und Anzeigen von Zeichenfolgen, Aufzählungen, Datumsangaben, Zeiten, Zeiträumen, Zahlen und Mengen erfüllt.

Kurze Antwort

"AwaitingFeedback".Humanize() => Awaiting feedback

Lange und beschreibende Antwort

Humanizer kann viel mehr arbeiten. Andere Beispiele sind:

"PascalCaseInputStringIsTurnedIntoSentence".Humanize() => "Pascal case input string is turned into sentence"
"Underscored_input_string_is_turned_into_sentence".Humanize() => "Underscored input string is turned into sentence"
"Can_return_title_Case".Humanize(LetterCasing.Title) => "Can Return Title Case"
"CanReturnLowerCase".Humanize(LetterCasing.LowerCase) => "can return lower case"

Der vollständige Code lautet:

using Humanizer;
using static System.Console;

namespace HumanizerConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            WriteLine("AwaitingFeedback".Humanize());
            WriteLine("PascalCaseInputStringIsTurnedIntoSentence".Humanize());
            WriteLine("Underscored_input_string_is_turned_into_sentence".Humanize());
            WriteLine("Can_return_title_Case".Humanize(LetterCasing.Title));
            WriteLine("CanReturnLowerCase".Humanize(LetterCasing.LowerCase));
        }
    }
}

Ausgabe

Erwarte Feedback

Die Eingabezeichenfolge für Pascal-Groß- und Kleinschreibung wird in einen Satz umgewandelt

Unterstrichene Eingabezeichenfolge wird in Satz umgewandelt. Kann Titel Groß- / Kleinschreibung zurückgeben

kann Kleinbuchstaben zurückgeben

Wenn Sie lieber Ihren eigenen C # -Code schreiben möchten, können Sie dies erreichen, indem Sie einige C # -Code-Inhalte schreiben, die bereits von anderen beantwortet wurden.

Banketeshvar Narayan
quelle
15

Bitte schön...

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CamelCaseToString
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(CamelCaseToString("ThisIsYourMasterCallingYou"));   
        }

        private static string CamelCaseToString(string str)
        {
            if (str == null || str.Length == 0)
                return null;

            StringBuilder retVal = new StringBuilder(32);

            retVal.Append(char.ToUpper(str[0]));
            for (int i = 1; i < str.Length; i++ )
            {
                if (char.IsLower(str[i]))
                {
                    retVal.Append(str[i]);
                }
                else
                {
                    retVal.Append(" ");
                    retVal.Append(char.ToLower(str[i]));
                }
            }

            return retVal.ToString();
        }
    }
}
Autodidakt
quelle
1
Sie sollten ToUpper () das erste Zeichen, sonst funktioniert Ihre Routine nicht mit echtem camelCase, nur PascalCase
David Wengier
Yup netter Fang, ich wusste, dass etwas nicht stimmte (aber ich konnte meinen Finger nicht darauf legen), als er sagte, "AwaitingFeedback" sei ein Kamelkoffer!
Autodidact
9

Dies ist genau wie @SSTA, aber effizienter als das Aufrufen von TrimStart.

Regex.Replace("ThisIsMyCapsDelimitedString", "(\\B[A-Z])", " $1")
Bryan Legend
quelle
9

Fand dies in der MvcContrib-Quelle, scheint hier noch nicht erwähnt zu sein.

return Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled).Trim();
JefClaes
quelle
4

Hier ist eine grundlegende Methode, die ich mit Regex entwickelt habe

public static string CamelCaseToSentence(this string value)
{
    var sb = new StringBuilder();
    var firstWord = true;

    foreach (var match in Regex.Matches(value, "([A-Z][a-z]+)|[0-9]+"))
    {
        if (firstWord)
        {
            sb.Append(match.ToString());
            firstWord = false;
        }
        else
        {
            sb.Append(" ");
            sb.Append(match.ToString().ToLower());
        }
    }

    return sb.ToString();
}

Es werden auch Zahlen abgespalten, die ich nicht angegeben habe, die aber nützlich wären.

Garry Shutler
quelle
4

Nur weil alle Regex verwendet haben (außer diesem Typen ), ist hier eine Implementierung StringBuilder, die in meinen Tests etwa fünfmal schneller war . Beinhaltet auch die Überprüfung auf Zahlen.

"SomeBunchOfCamelCase2".FromCamelCaseToSentence == "Some Bunch Of Camel Case 2"

public static string FromCamelCaseToSentence(this string input) {
    if(string.IsNullOrEmpty(input)) return input;

    var sb = new StringBuilder();
    // start with the first character -- consistent camelcase and pascal case
    sb.Append(char.ToUpper(input[0]));

    // march through the rest of it
    for(var i = 1; i < input.Length; i++) {
        // any time we hit an uppercase OR number, it's a new word
        if(char.IsUpper(input[i]) || char.IsDigit(input[i])) sb.Append(' ');
        // add regularly
        sb.Append(input[i]);
    }

    return sb.ToString();
}
drzaus
quelle
2

Ich würde einen regulären Ausdruck verwenden, ein Leerzeichen vor jedem Großbuchstaben einfügen und dann die gesamte Zeichenfolge verringern.

    string spacedString = System.Text.RegularExpressions.Regex.Replace(yourString, "\B([A-Z])", " \k");
    spacedString = spacedString.ToLower();
Antoine
quelle
Ich kenne C # nicht, aber ich denke nicht, dass Escapezeichen wie \ s im Ersetzungsabschnitt legal sind: Woher weiß die Sprache, ob Leerzeichen, Tabulatoren oder etwas anderes eingefügt werden müssen? :-)
PhiLho
Sie haben Recht, sollte einfacher sein, es durch ein klares "" zu ersetzen.
Antoine
Das einzige, was ich sagen würde, ist, dass "auf Feedback warten" wird
Garry Shutler
Nun, Sie müssen sicher das erste Leerzeichen entfernen und das erste Zeichen nach oben setzen. Fügen Sie möglicherweise ein "\ B" vor dem Muster hinzu, um nicht mit dem ersten Zeichen übereinzustimmen.
Antoine
2
string camel = "MyCamelCaseString";
string s = Regex.Replace(camel, "([A-Z])", " $1").ToLower().Trim();
Console.WriteLine(s.Substring(0,1).ToUpper() + s.Substring(1));

Bearbeiten: hat Ihre Gehäuseanforderungen nicht bemerkt, entsprechend geändert. Sie könnten einen Matchevaluator verwenden, um das Gehäuse zu machen, aber ich denke, ein Teilstring ist einfacher. Sie können es auch in einen zweiten regulären Ausdruck ersetzen, in dem Sie das erste Zeichen ändern

"^\w"

nach oben

\U (i think)
Andrew Bullock
quelle
2

Dies ist in JavaScript (oder PHP usw.) einfach, wo Sie eine Funktion im Ersetzungsaufruf definieren können:

var camel = "AwaitingFeedbackDearMaster";
var sentence = camel.replace(/([A-Z].)/g, function (c) { return ' ' + c.toLowerCase(); });
alert(sentence);

Obwohl ich das anfängliche Cap-Problem nicht gelöst habe ... :-)

Nun zur Java-Lösung:

String ToSentence(String camel)
{
  if (camel == null) return ""; // Or null...
  String[] words = camel.split("(?=[A-Z])");
  if (words == null) return "";
  if (words.length == 1) return words[0];
  StringBuilder sentence = new StringBuilder(camel.length());
  if (words[0].length() > 0) // Just in case of camelCase instead of CamelCase
  {
    sentence.append(words[0] + " " + words[1].toLowerCase());
  }
  else
  {
    sentence.append(words[1]);
  }
  for (int i = 2; i < words.length; i++)
  {
    sentence.append(" " + words[i].toLowerCase());
  }
  return sentence.toString();
}

System.out.println(ToSentence("AwaitingAFeedbackDearMaster"));
System.out.println(ToSentence(null));
System.out.println(ToSentence(""));
System.out.println(ToSentence("A"));
System.out.println(ToSentence("Aaagh!"));
System.out.println(ToSentence("stackoverflow"));
System.out.println(ToSentence("disableGPS"));
System.out.println(ToSentence("Ahh89Boo"));
System.out.println(ToSentence("ABC"));

Beachten Sie den Trick, den Satz zu teilen, ohne ein Zeichen zu verlieren ...

PhiLho
quelle
1

Pseudocode:

NewString = "";
Loop through every char of the string (skip the first one)
   If char is upper-case ('A'-'Z')
     NewString = NewString + ' ' + lowercase(char)
   Else
     NewString = NewString + char

Bessere Möglichkeiten können möglicherweise durch die Verwendung von Regex oder durch Routinen zum Ersetzen von Zeichenfolgen erreicht werden (ersetzen Sie 'X' durch 'x').

Schnaader
quelle
1

Eine xquery-Lösung, die sowohl für UpperCamel- als auch für LowerCamel-Fälle geeignet ist:

So geben Sie die Groß- und Kleinschreibung aus (nur das erste Zeichen des ersten Wortes wird groß geschrieben):

declare function content:sentenceCase($string)
{
let $firstCharacter := substring($string, 1, 1)
let $remainingCharacters := substring-after($string, $firstCharacter)
return
concat(upper-case($firstCharacter),lower-case(replace($remainingCharacters, '([A-Z])', ' $1')))
};

So geben Sie die Groß- und Kleinschreibung des Titels aus (erstes Zeichen jedes großgeschriebenen Wortes):

declare function content:titleCase($string)
{
let $firstCharacter := substring($string, 1, 1)
let $remainingCharacters := substring-after($string, $firstCharacter)
return
concat(upper-case($firstCharacter),replace($remainingCharacters, '([A-Z])', ' $1'))
};
Fraser
quelle
1

Ich habe etwas Ähnliches getan, und ich schätze es, mit dieser Diskussion einen Ausgangspunkt zu haben. Dies ist meine Lösung, die als Erweiterungsmethode für die Zeichenfolgenklasse im Kontext einer Konsolenanwendung platziert wird.

using System;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string piratese = "avastTharMatey";
            string ivyese = "CheerioPipPip";

            Console.WriteLine("{0}\n{1}\n", piratese.CamelCaseToString(), ivyese.CamelCaseToString());
            Console.WriteLine("For Pete\'s sake, man, hit ENTER!");
            string strExit = Console.ReadLine();
        }

    }

    public static class StringExtension
    {
        public static string CamelCaseToString(this string str)
        {
            StringBuilder retVal = new StringBuilder(32);

            if (!string.IsNullOrEmpty(str))
            {
                string strTrimmed = str.Trim();

                if (!string.IsNullOrEmpty(strTrimmed))
                {
                    retVal.Append(char.ToUpper(strTrimmed[0]));

                    if (strTrimmed.Length > 1)
                    {
                        for (int i = 1; i < strTrimmed.Length; i++)
                        {
                            if (char.IsUpper(strTrimmed[i])) retVal.Append(" ");

                            retVal.Append(char.ToLower(strTrimmed[i]));
                        }
                    }
                }
            }
            return retVal.ToString();
        }
    }
}
sscheider
quelle
1

Die meisten der vorhergehenden Antworten teilen Akronyme und Zahlen auf und fügen vor jedem Zeichen ein Leerzeichen ein. Ich wollte, dass Akronyme und Zahlen zusammengehalten werden, damit ich eine einfache Zustandsmaschine habe, die jedes Mal ein Leerzeichen ausgibt, wenn die Eingabe von einem Zustand in den anderen übergeht.

    /// <summary>
    /// Add a space before any capitalized letter (but not for a run of capitals or numbers)
    /// </summary>
    internal static string FromCamelCaseToSentence(string input)
    {
        if (string.IsNullOrEmpty(input)) return String.Empty;

        var sb = new StringBuilder();
        bool upper = true;

        for (var i = 0; i < input.Length; i++)
        {
            bool isUpperOrDigit = char.IsUpper(input[i]) || char.IsDigit(input[i]);
            // any time we transition to upper or digits, it's a new word
            if (!upper && isUpperOrDigit)
            {
                sb.Append(' ');
            }
            sb.Append(input[i]);
            upper = isUpperOrDigit;
        }

        return sb.ToString();
    }

Und hier sind einige Tests:

    [TestCase(null, ExpectedResult = "")]
    [TestCase("", ExpectedResult = "")]
    [TestCase("ABC", ExpectedResult = "ABC")]
    [TestCase("abc", ExpectedResult = "abc")]
    [TestCase("camelCase", ExpectedResult = "camel Case")]
    [TestCase("PascalCase", ExpectedResult = "Pascal Case")]
    [TestCase("Pascal123", ExpectedResult = "Pascal 123")]
    [TestCase("CustomerID", ExpectedResult = "Customer ID")]
    [TestCase("CustomABC123", ExpectedResult = "Custom ABC123")]
    public string CanSplitCamelCase(string input)
    {
        return FromCamelCaseToSentence(input);
    }
Ian Mercer
quelle
Gute Antwort. In meinem Projekt habe ich bool nextIsLower = i > 0 && i + 1 < source.Length && char.IsLower(source[i + 1]);den if-Ausdruck hinzugefügt und in geändert if ((!upper || nextIsLower) && isUpperOrDigit). Dadurch werden Akronyme von Wörtern getrennt, sodass CustomABCWith123 zu Custom ABC With 123 anstelle von Custom ABCWith 123 wird . Es kann Fälle geben, die ich nicht behandelt habe, und natürlich arbeiten A und ich nicht.
stritch000
0

Meistens schon hier beantwortet

Kleine Änderung der akzeptierten Antwort, um den zweiten und die nachfolgenden Großbuchstaben in Kleinbuchstaben umzuwandeln

if (char.IsUpper(text[i]))                
    newText.Append(' ');            
newText.Append(text[i]);

zu

if (char.IsUpper(text[i]))                
{
    newText.Append(' ');            
    newText.Append(char.ToLower(text[i]));
}
else
   newText.Append(text[i]);
Binärer Worrier
quelle