给定字符串“ThisStringHasNoSpacesButItDoesHaveCapitals”,什么是在大写字母之前添加空格的最好方法。所以结尾字符串是"This string Has No space But It Does Have大写"
下面是我使用正则表达式的尝试
System.Text.RegularExpressions.Regex.Replace(value, "[A-Z]", " $0")
给定字符串“ThisStringHasNoSpacesButItDoesHaveCapitals”,什么是在大写字母之前添加空格的最好方法。所以结尾字符串是"This string Has No space But It Does Have大写"
下面是我使用正则表达式的尝试
System.Text.RegularExpressions.Regex.Replace(value, "[A-Z]", " $0")
当前回答
受到二元忧虑者答案的启发,我尝试了一下。
结果如下:
/// <summary>
/// String Extension Method
/// Adds white space to strings based on Upper Case Letters
/// </summary>
/// <example>
/// strIn => "HateJPMorgan"
/// preserveAcronyms false => "Hate JP Morgan"
/// preserveAcronyms true => "Hate JPMorgan"
/// </example>
/// <param name="strIn">to evaluate</param>
/// <param name="preserveAcronyms" >determines saving acronyms (Optional => false) </param>
public static string AddSpaces(this string strIn, bool preserveAcronyms = false)
{
if (string.IsNullOrWhiteSpace(strIn))
return String.Empty;
var stringBuilder = new StringBuilder(strIn.Length * 2)
.Append(strIn[0]);
int i;
for (i = 1; i < strIn.Length - 1; i++)
{
var c = strIn[i];
if (Char.IsUpper(c) && (Char.IsLower(strIn[i - 1]) || (preserveAcronyms && Char.IsLower(strIn[i + 1]))))
stringBuilder.Append(' ');
stringBuilder.Append(c);
}
return stringBuilder.Append(strIn[i]).ToString();
}
测试使用秒表运行10000000次迭代和各种字符串长度和组合。
平均比二进制忧虑者的答案快50%(可能多一点)。
其他回答
除了马丁·布朗的回答,我也有一个关于数字的问题。例如:“Location2”或“Jan22”应该分别是“Location2”和“Jan22”。
下面是我的正则表达式,用的是Martin Brown的答案:
"((?<=\p{Ll})\p{Lu})|((?!\A)\p{Lu}(?>\p{Ll}))|((?<=[\p{Ll}\p{Lu}])\p{Nd})|((?<=\p{Nd})\p{Lu})"
这里有几个很好的网站,可以帮助你弄清楚每个部分的意思:
基于Java的正则表达式分析器(但适用于大多数。net正则表达式)
基于动作脚本的分析器
上面的正则表达式不能在动作脚本站点上工作,除非您将所有的\p{Ll}替换为[a-z],将\p{Lu}替换为[a-z],并将\p{Nd}替换为[0-9]。
下面是在SQL中如何做到这一点
create FUNCTION dbo.PascalCaseWithSpace(@pInput AS VARCHAR(MAX)) RETURNS VARCHAR(MAX)
BEGIN
declare @output varchar(8000)
set @output = ''
Declare @vInputLength INT
Declare @vIndex INT
Declare @vCount INT
Declare @PrevLetter varchar(50)
SET @PrevLetter = ''
SET @vCount = 0
SET @vIndex = 1
SET @vInputLength = LEN(@pInput)
WHILE @vIndex <= @vInputLength
BEGIN
IF ASCII(SUBSTRING(@pInput, @vIndex, 1)) = ASCII(Upper(SUBSTRING(@pInput, @vIndex, 1)))
begin
if(@PrevLetter != '' and ASCII(@PrevLetter) = ASCII(Lower(@PrevLetter)))
SET @output = @output + ' ' + SUBSTRING(@pInput, @vIndex, 1)
else
SET @output = @output + SUBSTRING(@pInput, @vIndex, 1)
end
else
begin
SET @output = @output + SUBSTRING(@pInput, @vIndex, 1)
end
set @PrevLetter = SUBSTRING(@pInput, @vIndex, 1)
SET @vIndex = @vIndex + 1
END
return @output
END
这是我的:
private string SplitCamelCase(string s)
{
Regex upperCaseRegex = new Regex(@"[A-Z]{1}[a-z]*");
MatchCollection matches = upperCaseRegex.Matches(s);
List<string> words = new List<string>();
foreach (Match match in matches)
{
words.Add(match.Value);
}
return String.Join(" ", words.ToArray());
}
正则表达式可以很好地工作(我甚至投票赞成Martin brown的答案),但是它们很昂贵(而且我个人认为任何超过两个字符的模式都非常迟钝)
这个函数
string AddSpacesToSentence(string text, bool preserveAcronyms)
{
if (string.IsNullOrWhiteSpace(text))
return string.Empty;
StringBuilder newText = new StringBuilder(text.Length * 2);
newText.Append(text[0]);
for (int i = 1; i < text.Length; i++)
{
if (char.IsUpper(text[i]))
if ((text[i - 1] != ' ' && !char.IsUpper(text[i - 1])) ||
(preserveAcronyms && char.IsUpper(text[i - 1]) &&
i < text.Length - 1 && !char.IsUpper(text[i + 1])))
newText.Append(' ');
newText.Append(text[i]);
}
return newText.ToString();
}
将在2,968,750个tick中执行100,000次,正则表达式将花费25,000,000个tick(这是编译的正则表达式)。
这是更好的,对于一个给定的更好的值(即更快),但它需要维护更多的代码。“更好”通常是相互竞争的需求的妥协。
更新 这是一个很长的时间,因为我看到这个,我才意识到时间没有更新,因为代码改变了(它只改变了一点)。
在'Abbbbbbbbb'重复100次(即1000字节)的字符串上,100,000次转换的运行需要手工编码函数4,517,177个节拍,下面的Regex需要59,435,719个节拍,使得手工编码函数的运行时间为Regex的7.6%。
更新2 它会考虑首字母缩略词吗?现在会了! if语句的逻辑是相当模糊的,正如你可以看到将它扩展为这样…
if (char.IsUpper(text[i]))
if (char.IsUpper(text[i - 1]))
if (preserveAcronyms && i < text.Length - 1 && !char.IsUpper(text[i + 1]))
newText.Append(' ');
else ;
else if (text[i - 1] != ' ')
newText.Append(' ');
... 一点用都没有!
这里是原始的简单方法,不担心缩略语
string AddSpacesToSentence(string text)
{
if (string.IsNullOrWhiteSpace(text))
return "";
StringBuilder newText = new StringBuilder(text.Length * 2);
newText.Append(text[0]);
for (int i = 1; i < text.Length; i++)
{
if (char.IsUpper(text[i]) && text[i - 1] != ' ')
newText.Append(' ');
newText.Append(text[i]);
}
return newText.ToString();
}
我开始做一个简单的扩展方法,基于二进制Worrier的代码,它将正确地处理首字母缩略词,并且是可重复的(不会破坏已经间隔的单词)。这是我的结果。
public static string UnPascalCase(this string text)
{
if (string.IsNullOrWhiteSpace(text))
return "";
var newText = new StringBuilder(text.Length * 2);
newText.Append(text[0]);
for (int i = 1; i < text.Length; i++)
{
var currentUpper = char.IsUpper(text[i]);
var prevUpper = char.IsUpper(text[i - 1]);
var nextUpper = (text.Length > i + 1) ? char.IsUpper(text[i + 1]) || char.IsWhiteSpace(text[i + 1]): prevUpper;
var spaceExists = char.IsWhiteSpace(text[i - 1]);
if (currentUpper && !spaceExists && (!nextUpper || !prevUpper))
newText.Append(' ');
newText.Append(text[i]);
}
return newText.ToString();
}
下面是这个函数通过的单元测试用例。我把他建议的大部分案例都加到了这个清单上。其中三个没有通过的(两个只是罗马数字)被注释掉了:
Assert.AreEqual("For You And I", "ForYouAndI".UnPascalCase());
Assert.AreEqual("For You And The FBI", "ForYouAndTheFBI".UnPascalCase());
Assert.AreEqual("A Man A Plan A Canal Panama", "AManAPlanACanalPanama".UnPascalCase());
Assert.AreEqual("DNS Server", "DNSServer".UnPascalCase());
Assert.AreEqual("For You And I", "For You And I".UnPascalCase());
Assert.AreEqual("Mount Mᶜ Kinley National Park", "MountMᶜKinleyNationalPark".UnPascalCase());
Assert.AreEqual("El Álamo Tejano", "ElÁlamoTejano".UnPascalCase());
Assert.AreEqual("The Ævar Arnfjörð Bjarmason", "TheÆvarArnfjörðBjarmason".UnPascalCase());
Assert.AreEqual("Il Caffè Macchiato", "IlCaffèMacchiato".UnPascalCase());
//Assert.AreEqual("Mister Dženan Ljubović", "MisterDženanLjubović".UnPascalCase());
//Assert.AreEqual("Ole King Henry Ⅷ", "OleKingHenryⅧ".UnPascalCase());
//Assert.AreEqual("Carlos Ⅴº El Emperador", "CarlosⅤºElEmperador".UnPascalCase());
Assert.AreEqual("For You And The FBI", "For You And The FBI".UnPascalCase());
Assert.AreEqual("A Man A Plan A Canal Panama", "A Man A Plan A Canal Panama".UnPascalCase());
Assert.AreEqual("DNS Server", "DNS Server".UnPascalCase());
Assert.AreEqual("Mount Mᶜ Kinley National Park", "Mount Mᶜ Kinley National Park".UnPascalCase());