대문자 앞에 공백 추가
"ThisString HasNoSpacesBut ItsHaveCapitals" 문자열을 고려할 때 대문자 앞에 공백을 추가하는 가장 좋은 방법은 무엇입니까?그래서 끝 문자열은 "이 문자열은 공백이 없지만 대문자는 있습니다"입니다.
ReGEx를 사용한 시도입니다.
System.Text.RegularExpressions.Regex.Replace(value, "[A-Z]", " $0")
정규식은 잘 작동할 것입니다(나는 마틴 브라운스의 대답에 투표하기도 했습니다). 하지만 그것들은 비쌉니다(그리고 개인적으로 저는 두 개의 문자보다 긴 패턴을 발견합니다).
이 함수
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개의 틱을 가져가고, 아래 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(' ');
전혀 도움이 되지 않습니다!
Acronyms에 대해 걱정하지 않는 원래의 간단한 방법은 다음과 같습니다.
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");
그래서 "드라이브는SCSI 호환'이 "드라이브가 SCSI 호환"이 됩니다.
성능 테스트는 하지 않았지만, 여기 linq와 한 줄로:
var val = "ThisIsAStringToTest";
val = string.Concat(val.Select(x => Char.IsUpper(x) ? " " + x : x.ToString())).TrimStart(' ');
이전 버전인 것은 알지만, 이 기능은 필요할 때 사용하는 확장 버전입니다.
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()
저는 바이너리 워리어의 코드에 기반한 간단한 확장 방법을 만들기 시작했습니다. 이 코드는 두문자어를 적절하게 처리하고 반복할 수 있습니다(이미 띄어쓴 단어가 섞이지 않습니다).여기 제 결과가 있습니다.
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
그나저나, 여기 있는 거의 모든 사람들이 첫 번째 방법, "최악"으로 표시된 방법을 선택했습니다.일부는 "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;
}
이 데이터 세트에서 "최고" 점수와 동일한 점수를 획득할 수 있으면 올바르게 완료한 것을 알 수 있습니다.그때까지, 당신은 그러지 않았어요.여기 있는 사람들 중 "좋아"보다 더 잘 한 사람은 없고, 대부분은 "최악의" 일을 했습니다.누군가 올바른 ♯코드를 게시하는 것을 기대합니다.
나는 StackOverflow의 강조 코드가 다시 비참하게 너무 빠르다는 것을 알아차렸습니다.그들은 여기서 언급된 나머지 부실한 접근법들이 했던 것과 동일한 (대부분은 아니지만) 오래된 레임을 만들고 있습니다.ASCII를 잠재울 시간이 오래되지 않았나요?그것은 더 이상 말이 되지 않으며, 당신이 가진 것이 전부인 척 하는 것은 단순히 잘못된 것입니다.그것은 잘못된 코드를 만듭니다.
이 정규식은 모든 대문자 앞에 공백 문자를 배치합니다.
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"
바이너리 워리어 씨, 저는 당신이 제안한 코드를 사용했고, 그것은 오히려 좋습니다, 저는 그것에 단지 하나의 작은 추가가 있습니다:
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])
은 'Average 은 ' 균평 ' 과것일 '와 같은 수 있는 했습니다.NOX'는 '평균 NOX'로 바뀌어야 하는데, '평균 NOX'로 표시되어야 하기 때문에 분명히 잘못된 것입니다.
슬프게도 이것은 여전히 '보낸 사람'이라는 텍스트를 가지고 있다면 버그를 가지고 있습니다.'시작'은 '시작에서'입니다.
이것을 고칠 생각이 있습니까?
문자열의 시작 부분에 공백을 넣지 말고 연속된 대문자 사이에 공백을 넣으십시오.여기에 있는 답변 중 일부는 이러한 점 중 하나 또는 두 가지 모두를 다루지 않습니다.정규식 이외에도 다른 방법이 있지만, 정규식을 사용하려면 다음을 시도하십시오.
Regex.Replace(value, @"\B[A-Z]", " $0")
그\B
는 부정된 것입니다.\b
그래서 그것은 단어가 아닌 단어를 나타냅니다.는패턴이와 "에서 "Y"와 일치한다는 것을 합니다.XYzabc
하지만 이 아닌Yzabc
또는X Yzabc
약간의 보너스로, 당신은 공백이 있는 문자열에 이것을 사용할 수 있고 그것은 그것들을 두 배로 늘어나지 않습니다.
@Martin Brown에서 영감을 받은 두 줄의 단순한 정규식은 현의 어디에서나 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();
}
내 것은 다음과 같습니다.
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());
}
당신이 가지고 있는 것은 완벽하게 작동합니다.다시 할당하는 것만 기억하세요.value
이 함수의 반환 값으로 설정합니다.
value = System.Text.RegularExpressions.Regex.Replace(value, "[A-Z]", " $0");
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
replaceAll("(?<=[^^\\p{Uppercase}])(?=[\\p{Uppercase}])"," ");
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();
}
Ruby에서 Regexp를 통해:
"FooBarBaz".gsub(/(?!^)(?=[A-Z])/, ' ') # => "Foo Bar Baz"
저는 케빈 스트라이커즈의 훌륭한 솔루션을 받아 VB로 전환했습니다.제가 갇혀 있으니까요.NET 3.5, 저는 IsNullOr도 작성해야 했습니다.화이트 스페이스.이것은 그의 모든 테스트를 통과합니다.
<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"
에게 좋은 기회인 것 같습니다.Aggregate
이 기능은 읽기 쉽도록 설계되었으며, 특별히 빠를 필요는 없습니다.
someString
.Aggregate(
new StringBuilder(),
(str, ch) => {
if (char.IsUpper(ch) && str.Length > 0)
str.Append(" ");
str.Append(ch);
return str;
}
).ToString();
이러한 답변 중 많은 부분이 다소 둔감한 것으로 나타났지만, 솔루션을 완전히 테스트하지는 않았지만, 필요한 부분에 적합하고, 두문자어를 처리해야 하며, 다른 IMO보다 훨씬 컴팩트하고 읽기 쉬웠습니다.
private string CamelCaseToSpaces(string s)
{
if (string.IsNullOrEmpty(s)) return string.Empty;
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < s.Length; i++)
{
stringBuilder.Append(s[i]);
int nextChar = i + 1;
if (nextChar < s.Length && char.IsUpper(s[nextChar]) && !char.IsUpper(s[i]))
{
stringBuilder.Append(" ");
}
}
return stringBuilder.ToString();
}
마틴 브라운의 답변 외에도, 저는 숫자에 대해서도 문제가 있었습니다.예를 들어, "위치 2" 또는 "Jan22"는 각각 "위치 2" 및 "Jan22"여야 합니다.
다음은 마틴 브라운의 대답을 사용한 저의 정규 표현입니다.
"((?<=\p{Ll})\p{Lu})|((?!\A)\p{Lu}(?>\p{Ll}))|((?<=[\p{Ll}\p{Lu}])\p{Nd})|((?<=\p{Nd})\p{Lu})"
다음은 각 부품이 의미하는 바를 파악하기 위한 몇 가지 훌륭한 사이트입니다.
Java 기반 정규식 분석기(대부분의 .net regex에서 작동)
는 작업 에서 사용자가 작업을 한 하지 않습니다\p{Ll}
와 함께[a-z]
,그\p{Lu}
와 함께[A-Z]
,그리고.\p{Nd}
와 함께[0-9]
.
Richard Priddys의 코멘트에 있는 Binary Worriers의 제안과 빌드를 기반으로 한 제 솔루션이 있습니다. 그러나 제공된 문자열에 공백이 존재할 수 있으므로 기존의 공백 옆에 공백이 추가되지 않습니다.
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가 제공한 답변을 본뜬 것입니다.이 메서드는 Acronyms만 자동으로 보존합니다.
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;
이 기능에 사용한 테스트 문자열의 결과는 다음과 같습니다.
- "hello World" -> "hello World"
- "Hello World" -> "Hello World"
- "안녕하세요 ABC월드" -> "안녕하세요 ABC월드"
- "Hello World ABC" -> "Hello World ABC"
- "ABC 헬로 월드" -> "ABC 헬로 월드"
- "ABC HELLO WORLD" -> "ABC HELLO WORLD"
- "ABCHELLOOROLD" -> "ABCHELLOOROLD"
- "A" -> "A"
ASCII 문자로만 구성된 입력 문자열에 대한 C# 솔루션입니다.정규식은 문자열의 시작 부분에 나타나는 대문자를 무시하기 위해 부정적인 뒤보기를 통합합니다.정규식을 사용합니다.원하는 문자열을 반환하려면 대체()를 선택합니다.
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.)
이전의 모든 답변은 너무 복잡해 보였습니다.
저는 대문자와 _사용된 문자열이 섞인 문자열을 가지고 있었습니다._, "로 만들려면 ()를 바꾸고 대문자에 공백을 추가하기 위해 다음을 사용합니다.
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".
언급URL : https://stackoverflow.com/questions/272633/add-spaces-before-capital-letters
'programing' 카테고리의 다른 글
도커 파일:여러 환경 변수를 한 줄로 설정 (0) | 2023.08.30 |
---|---|
이미지 처리를 위한 매우 빠른 Memcpy? (0) | 2023.08.30 |
Powershell에서 JSON으로 변환할 때 탭 너비를 변경하는 방법 (0) | 2023.08.30 |
order 절 및 더 큰 제한 Maria가 있는 인덱스를 사용하지 않는 단순 SQL 쿼리DB (0) | 2023.08.25 |
AJAX를 사용하여 변수를 PHP로 전달하고 AJAX를 사용하여 변수를 다시 검색 (0) | 2023.08.25 |