"ThisStringHasNoSpacesButItDoesHaveCapitals"라는 문자열이 주어지면 대문자 앞에 공백을 추가하는 가장 좋은 방법은 무엇입니까? 끝 문자열은 "이 문자열에는 공백이 없지만 대문자가 있습니다"입니다.
다음은 RegEx를 사용한 시도입니다.
System.Text.RegularExpressions.Regex.Replace(value, "[A-Z]", " $0")
"ThisStringHasNoSpacesButItDoesHaveCapitals"라는 문자열이 주어지면 대문자 앞에 공백을 추가하는 가장 좋은 방법은 무엇입니까? 끝 문자열은 "이 문자열에는 공백이 없지만 대문자가 있습니다"입니다.
다음은 RegEx를 사용한 시도입니다.
System.Text.RegularExpressions.Regex.Replace(value, "[A-Z]", " $0")
답변:
정규 표현식이 제대로 작동하지만 (Martin Browns 답변에 투표하기까지 했음) 비용이 많이 듭니다.
이 기능
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 틱으로 100,000 번, 정규식은 25,000,000 틱 (및 정규식이 컴파일 된 틱)이 걸립니다.
주어진 값이 더 좋을수록 (즉 더 빠름) 더 낫지 만 유지해야 할 코드는 더 많습니다. "더 나은"은 종종 경쟁 요구 사항을 타협합니다.
도움이 되었기를 바랍니다 :)
업데이트
이것을 살펴본 후 오랜 시간이 걸렸으며 코드가 변경된 후 타이밍이 업데이트되지 않았다는 것을 깨달았습니다.
'Abbbbbbbbb'이 100 번 반복 된 문자열 (즉, 1,000 바이트)이있는 문자열에서 100,000 회의 변환은 수작업으로 코딩 된 함수 4,517,177 틱을 취하고 아래의 정규식은 59,435,719를 수행하여 Hand coded 함수를 수행하는 시간의 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();
}
솔루션에 첫 번째 문자 T 앞에 공백을 넣는 문제가 있으므로
" This String..." instead of "This String..."
이 문제를 해결하려면 앞에 소문자를 찾은 다음 중간에 공백을 삽입하십시오.
newValue = Regex.Replace(value, "([a-z])([A-Z])", "$1 $2");
편집 1 :
사용 @"(\p{Ll})(\p{Lu})"
하면 악센트 부호가있는 문자도 선택됩니다.
편집 2 :
문자열에 두문자어가 포함될 수있는 경우 다음을 사용할 수 있습니다.
newValue = Regex.Replace(value, @"((?<=\p{Ll})\p{Lu})|((?!\A)\p{Lu}(?>\p{Ll}))", " $0");
따라서 "DriveIsSCSICompatible"은 "Drive Is SCSI Compatible"이됩니다.
"([^A-Z\\s])([A-Z])"
두문자어 도 사용할 수 있습니까?
나는 이것이 오래된 것임을 알고 있지만, 이것을해야 할 때 사용하는 확장입니다.
public static class Extensions
{
public static string ToSentence( this string Input )
{
return new string(Input.SelectMany((c, i) => i > 0 && char.IsUpper(c) ? new[] { ' ', c } : new[] { c }).ToArray());
}
}
이것은 당신이 사용할 수 있습니다 MyCasedString.ToSentence()
TrimStart(' ')
하면 선행 공간이 제거됩니다.
SelectMany
색인을 포함하는 과부하를 사용하도록 확장을 변경했습니다 .이 방법으로 첫 번째 문자와에 대한 추가 호출의 불필요한 잠재적 인 오버 헤드를 피할 수 TrimStart(' ')
있습니다. 롭
이진 걱정의 코드를 기반으로 간단한 확장 방법을 사용하여 약어를 올바르게 처리하고 반복 할 수 있습니다 (이미 단어 간격이 엉망이 아닙니다). 여기 내 결과가 있습니다.
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();
}
이 함수가 통과하는 단위 테스트 사례는 다음과 같습니다. tchrist가 제안한 사례의 대부분을이 목록에 추가했습니다. 통과하지 못하는 세 가지 (두 개는 로마 숫자 일뿐입니다)는 주석 처리됩니다.
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());
이 모든 솔루션은 현대 텍스트에는 본질적으로 잘못되었습니다. 대소 문자를 이해하는 것을 사용해야합니다. Bob이 다른 언어를 요청했기 때문에 Perl에게 몇 가지를 드리겠습니다.
최악에서 최고에 이르는 네 가지 솔루션을 제공합니다. 가장 좋은 것만 항상 옳습니다. 다른 사람들에게는 문제가 있습니다. 다음은 작동하는 것과 작동하지 않는 위치 및 위치를 보여주는 테스트 실행입니다. 공백을 넣은 위치를 볼 수 있도록 밑줄을 사용했으며, 잘못된 것으로 잘못 표시했습니다.
Testing TheLoneRanger
Worst: The_Lone_Ranger
Ok: The_Lone_Ranger
Better: The_Lone_Ranger
Best: The_Lone_Ranger
Testing MountMᶜKinleyNationalPark
[WRONG] Worst: Mount_MᶜKinley_National_Park
[WRONG] Ok: Mount_MᶜKinley_National_Park
[WRONG] Better: Mount_MᶜKinley_National_Park
Best: Mount_Mᶜ_Kinley_National_Park
Testing ElÁlamoTejano
[WRONG] Worst: ElÁlamo_Tejano
Ok: El_Álamo_Tejano
Better: El_Álamo_Tejano
Best: El_Álamo_Tejano
Testing TheÆvarArnfjörðBjarmason
[WRONG] Worst: TheÆvar_ArnfjörðBjarmason
Ok: The_Ævar_Arnfjörð_Bjarmason
Better: The_Ævar_Arnfjörð_Bjarmason
Best: The_Ævar_Arnfjörð_Bjarmason
Testing IlCaffèMacchiato
[WRONG] Worst: Il_CaffèMacchiato
Ok: Il_Caffè_Macchiato
Better: Il_Caffè_Macchiato
Best: Il_Caffè_Macchiato
Testing MisterDženanLjubović
[WRONG] Worst: MisterDženanLjubović
[WRONG] Ok: MisterDženanLjubović
Better: Mister_Dženan_Ljubović
Best: Mister_Dženan_Ljubović
Testing OleKingHenryⅧ
[WRONG] Worst: Ole_King_HenryⅧ
[WRONG] Ok: Ole_King_HenryⅧ
[WRONG] Better: Ole_King_HenryⅧ
Best: Ole_King_Henry_Ⅷ
Testing CarlosⅤºElEmperador
[WRONG] Worst: CarlosⅤºEl_Emperador
[WRONG] Ok: CarlosⅤº_El_Emperador
[WRONG] Better: CarlosⅤº_El_Emperador
Best: Carlos_Ⅴº_El_Emperador
BTW, 여기에있는 거의 모든 사람들이 "Worst"라고 표시된 첫 번째 방법을 선택했습니다. "OK"라고 표시된 두 번째 방법을 선택한 사람이 있습니다. 그러나 저보다 먼저 "더 나은"또는 "최상의"접근 방식을 수행하는 방법을 보여준 사람은 없습니다.
다음은 네 가지 방법으로 테스트 프로그램입니다.
#!/usr/bin/env perl
use utf8;
use strict;
use warnings;
# First I'll prove these are fine variable names:
my (
$TheLoneRanger ,
$MountMᶜKinleyNationalPark ,
$ElÁlamoTejano ,
$TheÆvarArnfjörðBjarmason ,
$IlCaffèMacchiato ,
$MisterDženanLjubović ,
$OleKingHenryⅧ ,
$CarlosⅤºElEmperador ,
);
# Now I'll load up some string with those values in them:
my @strings = qw{
TheLoneRanger
MountMᶜKinleyNationalPark
ElÁlamoTejano
TheÆvarArnfjörðBjarmason
IlCaffèMacchiato
MisterDženanLjubović
OleKingHenryⅧ
CarlosⅤºElEmperador
};
my($new, $best, $ok);
my $mask = " %10s %-8s %s\n";
for my $old (@strings) {
print "Testing $old\n";
($best = $old) =~ s/(?<=\p{Lowercase})(?=[\p{Uppercase}\p{Lt}])/_/g;
($new = $old) =~ s/(?<=[a-z])(?=[A-Z])/_/g;
$ok = ($new ne $best) && "[WRONG]";
printf $mask, $ok, "Worst:", $new;
($new = $old) =~ s/(?<=\p{Ll})(?=\p{Lu})/_/g;
$ok = ($new ne $best) && "[WRONG]";
printf $mask, $ok, "Ok:", $new;
($new = $old) =~ s/(?<=\p{Ll})(?=[\p{Lu}\p{Lt}])/_/g;
$ok = ($new ne $best) && "[WRONG]";
printf $mask, $ok, "Better:", $new;
($new = $old) =~ s/(?<=\p{Lowercase})(?=[\p{Uppercase}\p{Lt}])/_/g;
$ok = ($new ne $best) && "[WRONG]";
printf $mask, $ok, "Best:", $new;
}
이 데이터 세트에서 "최고"와 동일한 점수를 매길 수 있으면 올바르게 수행 한 것입니다. 그때까지는 그렇지 않았습니다. 여기서 다른 어느 누구도 "Ok"보다 나은 작업을 수행하지 않았으며 대부분 "Worst"를 수행했습니다. 누군가 올바른 ℂ♯ 코드를 게시하기를 기대합니다.
StackOverflow의 강조 표시 코드가 다시 비참하게 다루어졌습니다. 그들은 여기에 언급 된 나머지 가난한 접근 방식과 거의 같은 오래된 절름발이를 만들고 있습니다. ASCII를 쉬게하는 데 시간이 오래 걸리지 않습니까? 더 이상 말이되지 않으며, 당신이 가진 전부인 척하는 것은 단순히 잘못입니다. 코드가 잘못되었습니다.
이진 걱정, 나는 당신의 제안 된 코드를 사용했으며, 약간 좋습니다. 단지 하나의 추가 사항이 있습니다.
public static string AddSpacesToSentence(string text)
{
if (string.IsNullOrEmpty(text))
return "";
StringBuilder newText = new StringBuilder(text.Length * 2);
newText.Append(text[0]);
for (int i = 1; i < result.Length; i++)
{
if (char.IsUpper(result[i]) && !char.IsUpper(result[i - 1]))
{
newText.Append(' ');
}
else if (i < result.Length)
{
if (char.IsUpper(result[i]) && !char.IsUpper(result[i + 1]))
newText.Append(' ');
}
newText.Append(result[i]);
}
return newText.ToString();
}
조건을 추가했습니다 !char.IsUpper(text[i - 1])
. 이로 인해 'AverageNOX'와 같은 것이 'Average NOX'로 바뀌는 버그가 수정되었습니다. 'Average NOX'를 읽어야하므로 분명히 잘못되었습니다.
슬프게도 여전히 'FromAStart'라는 텍스트가 있으면 'From AStart'가 표시되는 버그가 있습니다.
이것을 고치는 것에 대한 생각이 있습니까?
if (char.IsUpper(text[i]) && !(char.IsUpper(text[i - 1]) && char.IsUpper(text[i + 1])))
테스트 결과 : "시작에서", "시작에서", "시작에서" 올바른 결과입니다. 그러나 i < text.Length - 1
마지막 문자를 무시하고 범위를 벗어난 예외를 방지하려면 for 루프 조건 이 필요합니다 .
내 꺼야 :
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());
}
<pre><code>code</code></pre>
Markdown 구문 대신 블록에 숨겨져있었습니다 . 그를 하향 투표 할 필요가 없습니다 (귀하의 경우).
확인은 확인이 되지 않은 문자열의 시작 부분에 공백을 넣어,하지만 당신은 하는 연속 자본 사이에 그들을 가하고. 여기에있는 답변 중 일부는 그러한 요점 중 하나 또는 둘 다를 다루지 않습니다. 정규 표현식 이외의 다른 방법이 있지만, 그것을 사용하려면 다음을 시도하십시오.
Regex.Replace(value, @"\B[A-Z]", " $0")
는 \B
부정 된이다 \b
는 비 단어 경계를 나타냅니다 있도록. 패턴이에서 "Y"와 일치 XYzabc
하지만 in Yzabc
또는 와는 일치 하지 않음을 의미합니다 X Yzabc
. 약간의 보너스로 공백이있는 문자열에 이것을 사용할 수 있으며 두 배로 늘리지 않습니다.
이 정규식은 모든 대문자 앞에 공백 문자를 배치합니다.
using System.Text.RegularExpressions;
const string myStringWithoutSpaces = "ThisIsAStringWithoutSpaces";
var myStringWithSpaces = Regex.Replace(myStringWithoutSpaces, "([A-Z])([a-z]*)", " $1$2");
"$ 1 $ 2"이면 앞에있는 공간을 염두에두면됩니다.
이것이 결과입니다 :
"This Is A String Without Spaces"
"([A-Z0-9])([a-z]*)"
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
@MartinBrown에서 영감을 얻은 Two Lines of Simple Regex는 문자열의 아무 곳이나 Acyronyms를 포함하여 이름을 확인합니다.
public string ResolveName(string name)
{
var tmpDisplay = Regex.Replace(name, "([^A-Z ])([A-Z])", "$1 $2");
return Regex.Replace(tmpDisplay, "([A-Z]+)([A-Z][^A-Z$])", "$1 $2").Trim();
}
static string AddSpacesToColumnName(string columnCaption)
{
if (string.IsNullOrWhiteSpace(columnCaption))
return "";
StringBuilder newCaption = new StringBuilder(columnCaption.Length * 2);
newCaption.Append(columnCaption[0]);
int pos = 1;
for (pos = 1; pos < columnCaption.Length-1; pos++)
{
if (char.IsUpper(columnCaption[pos]) && !(char.IsUpper(columnCaption[pos - 1]) && char.IsUpper(columnCaption[pos + 1])))
newCaption.Append(' ');
newCaption.Append(columnCaption[pos]);
}
newCaption.Append(columnCaption[pos]);
return newCaption.ToString();
}
Kevin Strikers의 탁월한 솔루션을 VB로 변환했습니다. .NET 3.5에 잠겨 있기 때문에 IsNullOrWhiteSpace도 작성해야했습니다. 이것은 그의 모든 테스트를 통과합니다.
<Extension()>
Public Function IsNullOrWhiteSpace(value As String) As Boolean
If value Is Nothing Then
Return True
End If
For i As Integer = 0 To value.Length - 1
If Not Char.IsWhiteSpace(value(i)) Then
Return False
End If
Next
Return True
End Function
<Extension()>
Public Function UnPascalCase(text As String) As String
If text.IsNullOrWhiteSpace Then
Return String.Empty
End If
Dim newText = New StringBuilder()
newText.Append(text(0))
For i As Integer = 1 To text.Length - 1
Dim currentUpper = Char.IsUpper(text(i))
Dim prevUpper = Char.IsUpper(text(i - 1))
Dim nextUpper = If(text.Length > i + 1, Char.IsUpper(text(i + 1)) Or Char.IsWhiteSpace(text(i + 1)), prevUpper)
Dim spaceExists = Char.IsWhiteSpace(text(i - 1))
If (currentUpper And Not spaceExists And (Not nextUpper Or Not prevUpper)) Then
newText.Append(" ")
End If
newText.Append(text(i))
Next
Return newText.ToString()
End Function
질문은 조금 오래되었지만 요즘 Nuget에는 사람이 읽을 수있는 텍스트로 많은 다른 변환뿐만 아니라 정확하게 수행하는 멋진 라이브러리가 있습니다.
GitHub 또는 Nuget 에서 Humanizer 를 확인하십시오 .
예
"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"
"Underscored_input_String_is_turned_INTO_sentence".Humanize() => "Underscored input String is turned INTO sentence"
// acronyms are left intact
"HTML".Humanize() => "HTML"
Martin Brown의 답변 외에도 숫자에 문제가있었습니다. 예를 들어 "Location2"또는 "Jan22"는 각각 "Location 2"및 "Jan 22"여야합니다.
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}
with [a-z]
, \p{Lu}
with with [A-Z]
및 \p{Nd}
with를 모두 바꾸지 않으면 액션 스크립트 사이트에서 작동하지 않습니다 [0-9]
.
이진 걱정 제안 및 Richard Priddys의 의견을 바탕으로 한 내 솔루션은 다음과 같습니다. 또한 제공된 문자열에 공백이있을 수 있으므로 기존 공백 옆에 공백이 추가되지 않습니다.
public string AddSpacesBeforeUpperCase(string nonSpacedString)
{
if (string.IsNullOrEmpty(nonSpacedString))
return string.Empty;
StringBuilder newText = new StringBuilder(nonSpacedString.Length * 2);
newText.Append(nonSpacedString[0]);
for (int i = 1; i < nonSpacedString.Length; i++)
{
char currentChar = nonSpacedString[i];
// If it is whitespace, we do not need to add another next to it
if(char.IsWhiteSpace(currentChar))
{
continue;
}
char previousChar = nonSpacedString[i - 1];
char nextChar = i < nonSpacedString.Length - 1 ? nonSpacedString[i + 1] : nonSpacedString[i];
if (char.IsUpper(currentChar) && !char.IsWhiteSpace(nextChar)
&& !(char.IsUpper(previousChar) && char.IsUpper(nextChar)))
{
newText.Append(' ');
}
else if (i < nonSpacedString.Length)
{
if (char.IsUpper(currentChar) && !char.IsWhiteSpace(nextChar) && !char.IsUpper(nextChar))
{
newText.Append(' ');
}
}
newText.Append(currentChar);
}
return newText.ToString();
}
이 같은 질문에 대답하는 C ++ 함수를 찾는 사람은 다음을 사용할 수 있습니다. 이것은 @Binary Worrier의 답변을 모델로합니다. 이 방법은 약어를 자동으로 유지합니다.
using namespace std;
void AddSpacesToSentence(string& testString)
stringstream ss;
ss << testString.at(0);
for (auto it = testString.begin() + 1; it != testString.end(); ++it )
{
int index = it - testString.begin();
char c = (*it);
if (isupper(c))
{
char prev = testString.at(index - 1);
if (isupper(prev))
{
if (index < testString.length() - 1)
{
char next = testString.at(index + 1);
if (!isupper(next) && next != ' ')
{
ss << ' ';
}
}
}
else if (islower(prev))
{
ss << ' ';
}
}
ss << c;
}
cout << ss.str() << endl;
이 함수에 사용한 테스트 문자열은 다음과 같습니다.
C #을 ASCII 문자로 구성되어 입력 문자열에 대한 솔루션을 제공합니다. 정규식 통합 부정적인 lookbehind 문자열의 시작 부분에 나타납니다 자본 (대문자) 편지를 무시합니다. Regex.Replace () 를 사용 하여 원하는 문자열을 반환합니다.
regex101.com 데모 도 참조하십시오 .
using System;
using System.Text.RegularExpressions;
public class RegexExample
{
public static void Main()
{
var text = "ThisStringHasNoSpacesButItDoesHaveCapitals";
// Use negative lookbehind to match all capital letters
// that do not appear at the beginning of the string.
var pattern = "(?<!^)([A-Z])";
var rgx = new Regex(pattern);
var result = rgx.Replace(text, " $1");
Console.WriteLine("Input: [{0}]\nOutput: [{1}]", text, result);
}
}
예상 출력 :
Input: [ThisStringHasNoSpacesButItDoesHaveCapitals]
Output: [This String Has No Spaces But It Does Have Capitals]
업데이트 : 약어 (대문자 문자 순서) 도 처리하는 변형이 있습니다 .
regex101.com 데모 및 ideone.com 데모 도 참조하십시오 .
using System;
using System.Text.RegularExpressions;
public class RegexExample
{
public static void Main()
{
var text = "ThisStringHasNoSpacesASCIIButItDoesHaveCapitalsLINQ";
// Use positive lookbehind to locate all upper-case letters
// that are preceded by a lower-case letter.
var patternPart1 = "(?<=[a-z])([A-Z])";
// Used positive lookbehind and lookahead to locate all
// upper-case letters that are preceded by an upper-case
// letter and followed by a lower-case letter.
var patternPart2 = "(?<=[A-Z])([A-Z])(?=[a-z])";
var pattern = patternPart1 + "|" + patternPart2;
var rgx = new Regex(pattern);
var result = rgx.Replace(text, " $1$2");
Console.WriteLine("Input: [{0}]\nOutput: [{1}]", text, result);
}
}
예상 출력 :
Input: [ThisStringHasNoSpacesASCIIButItDoesHaveCapitalsLINQ]
Output: [This String Has No Spaces ASCII But It Does Have Capitals LINQ]
단어 앞에 공백을 넣지 않는보다 철저한 솔루션이 있습니다.
참고 : 여러 정규 표현식을 사용했습니다 (간결하지는 않지만 약어 및 단일 문자를 처리합니다)
Dim s As String = "ThisStringHasNoSpacesButItDoesHaveCapitals"
s = System.Text.RegularExpressions.Regex.Replace(s, "([a-z])([A-Z](?=[A-Z])[a-z]*)", "$1 $2")
s = System.Text.RegularExpressions.Regex.Replace(s, "([A-Z])([A-Z][a-z])", "$1 $2")
s = System.Text.RegularExpressions.Regex.Replace(s, "([a-z])([A-Z][a-z])", "$1 $2")
s = System.Text.RegularExpressions.Regex.Replace(s, "([a-z])([A-Z][a-z])", "$1 $2") // repeat a second time
에서 :
"ThisStringHasNoSpacesButItDoesHaveCapitals"
"IAmNotAGoat"
"LOLThatsHilarious!"
"ThisIsASMSMessage"
아웃 :
"This String Has No Spaces But It Does Have Capitals"
"I Am Not A Goat"
"LOL Thats Hilarious!"
"This Is ASMS Message" // (Difficult to handle single letter words when they are next to acronyms.)
이전의 모든 응답은 너무 복잡해 보였다.
나는 대문자와 _이 혼합 된 문자열을 가지고 있었으므로 string.Replace ()를 사용하여 _, ""를 만들고 다음을 사용하여 대문자에 공백을 추가했습니다.
for (int i = 0; i < result.Length; i++)
{
if (char.IsUpper(result[i]))
{
counter++;
if (i > 1) //stops from adding a space at if string starts with Capital
{
result = result.Insert(i, " ");
i++; //Required** otherwise stuck in infinite
//add space loop over a single capital letter.
}
}
}
Binary Worrier의 답변에서 영감을 얻었습니다.
결과는 다음과 같습니다.
/// <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 반복 및 다양한 문자열 길이 및 조합을 실행하는 스톱워치를 사용하여 테스트했습니다.
Binary Worrier의 답변보다 평균 50 % 빠릅니다.
private string GetProperName(string Header)
{
if (Header.ToCharArray().Where(c => Char.IsUpper(c)).Count() == 1)
{
return Header;
}
else
{
string ReturnHeader = Header[0].ToString();
for(int i=1; i<Header.Length;i++)
{
if (char.IsLower(Header[i-1]) && char.IsUpper(Header[i]))
{
ReturnHeader += " " + Header[i].ToString();
}
else
{
ReturnHeader += Header[i].ToString();
}
}
return ReturnHeader;
}
return Header;
}
여기에는 두문자어와 복수형이 포함되며 허용되는 답변보다 약간 빠릅니다.
public string Sentencify(string value)
{
if (string.IsNullOrWhiteSpace(value))
return string.Empty;
string final = string.Empty;
for (int i = 0; i < value.Length; i++)
{
if (i != 0 && Char.IsUpper(value[i]))
{
if (!Char.IsUpper(value[i - 1]))
final += " ";
else if (i < (value.Length - 1))
{
if (!Char.IsUpper(value[i + 1]) && !((value.Length >= i && value[i + 1] == 's') ||
(value.Length >= i + 1 && value[i + 1] == 'e' && value[i + 2] == 's')))
final += " ";
}
}
final += value[i];
}
return final;
}
다음 테스트를 통과합니다.
string test1 = "RegularOTs";
string test2 = "ThisStringHasNoSpacesASCIIButItDoesHaveCapitalsLINQ";
string test3 = "ThisStringHasNoSpacesButItDoesHaveCapitals";
로 fold
알려진 구현 Aggregate
:
public static string SpaceCapitals(this string arg) =>
new string(arg.Aggregate(new List<Char>(),
(accum, x) =>
{
if (Char.IsUpper(x) &&
accum.Any() &&
// prevent double spacing
accum.Last() != ' ' &&
// prevent spacing acronyms (ASCII, SCSI)
!Char.IsUpper(accum.Last()))
{
accum.Add(' ');
}
accum.Add(x);
return accum;
}).ToArray());
요청 외에도이 구현은 선행, 내부, 후행 공백 및 두문자어를 올바르게 저장합니다.
" SpacedWord " => " Spaced Word ",
"Inner Space" => "Inner Space",
"SomeACRONYM" => "Some ACRONYM".
소문자, 대문자 또는 숫자 뒤에 공백을 추가하는 간단한 방법입니다.
string AddSpacesToSentence(string value, bool spaceLowerChar = true, bool spaceDigitChar = true, bool spaceSymbolChar = false)
{
var result = "";
for (int i = 0; i < value.Length; i++)
{
char currentChar = value[i];
char nextChar = value[i < value.Length - 1 ? i + 1 : value.Length - 1];
if (spaceLowerChar && char.IsLower(currentChar) && !char.IsLower(nextChar))
{
result += value[i] + " ";
}
else if (spaceDigitChar && char.IsDigit(currentChar) && !char.IsDigit(nextChar))
{
result += value[i] + " ";
}
else if(spaceSymbolChar && char.IsSymbol(currentChar) && !char.IsSymbol(nextChar))
{
result += value[i];
}
else
{
result += value[i];
}
}
return result;
}