select * from yourtable
group by id
having rev=max(rev);
Самый быстрый способ? Итерации по строке и построение второй копии в символе StringBuilder
по символу, только копирование одного пробела для каждой группы пробелов.
. Более простые для ввода Replace
варианты создадут загрузку лишнего (или время траты, создающее регулярное выражение DFA).
Редактировать с помощью результатов сравнения:
Используя http://ideone.com/h6pw3 , с n = 50 (пришлось уменьшить его на идеон, потому что потребовалось так много времени, чтобы убить мой процесс), я получаю:
Regex: 7771ms.
Stringbuilder: 894ms.
Что действительно так, как ожидалось,
Regex
ужасно неэффективно для чего-то такого простого.
string yourWord = "beep boop baap beep boop baap beep";
yourWord = yourWord .Replace(" ", " |").Replace("| ", "").Replace("|", "");
Я знаю, что это действительно старый, но самый простой способ сглаживания пробелов (заменить любой повторяющийся символ пробела одним символом «пробел») следующим образом:
public static string CompactWhitespace(string astring)
{
if (!string.IsNullOrEmpty(astring))
{
bool found = false;
StringBuilder buff = new StringBuilder();
foreach (char chr in astring.Trim())
{
if (char.IsWhiteSpace(chr))
{
if (found)
{
continue;
}
found = true;
buff.Append(' ');
}
else
{
if (found)
{
found = false;
}
buff.Append(chr);
}
}
return buff.ToString();
}
return string.Empty;
}
public string GetCorrectString(string IncorrectString)
{
string[] strarray = IncorrectString.Split(' ');
var sb = new StringBuilder();
foreach (var str in strarray)
{
if (str != string.Empty)
{
sb.Append(str).Append(' ');
}
}
return sb.ToString().Trim();
}
Этот фрагмент кода работает хорошо. Я не измеряю производительность.
string text = " hello - world, here we go !!! a bc ";
string.Join(" ", text.Split().Where(x => x != ""));
// Output
// "hello - world, here we go !!! a bc"
Немного поздно, но я сделал некоторый бенчмаркинг, чтобы получить самый быстрый способ удалить лишние пробелы. Если есть более быстрые ответы, я бы хотел их добавить.
Результаты:
Код:
public class RemoveExtraWhitespaces
{
public static string WithRegex(string text)
{
return Regex.Replace(text, @"\s+", " ");
}
public static string WithRegexCompiled(Regex compiledRegex, string text)
{
return compiledRegex.Replace(text, " ");
}
public static string NormalizeWhiteSpace(string input)
{
if (string.IsNullOrEmpty(input))
return string.Empty;
int current = 0;
char[] output = new char[input.Length];
bool skipped = false;
foreach (char c in input.ToCharArray())
{
if (char.IsWhiteSpace(c))
{
if (!skipped)
{
if (current > 0)
output[current++] = ' ';
skipped = true;
}
}
else
{
skipped = false;
output[current++] = c;
}
}
return new string(output, 0, current);
}
public static string NormalizeWhiteSpaceForLoop(string input)
{
int len = input.Length,
index = 0,
i = 0;
var src = input.ToCharArray();
bool skip = false;
char ch;
for (; i < len; i++)
{
ch = src[i];
switch (ch)
{
case '\u0020':
case '\u00A0':
case '\u1680':
case '\u2000':
case '\u2001':
case '\u2002':
case '\u2003':
case '\u2004':
case '\u2005':
case '\u2006':
case '\u2007':
case '\u2008':
case '\u2009':
case '\u200A':
case '\u202F':
case '\u205F':
case '\u3000':
case '\u2028':
case '\u2029':
case '\u0009':
case '\u000A':
case '\u000B':
case '\u000C':
case '\u000D':
case '\u0085':
if (skip) continue;
src[index++] = ch;
skip = true;
continue;
default:
skip = false;
src[index++] = ch;
continue;
}
}
return new string(src, 0, index);
}
}
Тесты:
[TestFixture]
public class RemoveExtraWhitespacesTest
{
private const string _text = "foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo ";
private const string _expected = "foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo foo bar foobar moo ";
private const int _iterations = 10000;
[Test]
public void Regex()
{
var result = TimeAction("Regex", () => RemoveExtraWhitespaces.WithRegex(_text));
Assert.AreEqual(_expected, result);
}
[Test]
public void RegexCompiled()
{
var compiledRegex = new Regex(@"\s+", RegexOptions.Compiled);
var result = TimeAction("RegexCompiled", () => RemoveExtraWhitespaces.WithRegexCompiled(compiledRegex, _text));
Assert.AreEqual(_expected, result);
}
[Test]
public void NormalizeWhiteSpace()
{
var result = TimeAction("NormalizeWhiteSpace", () => RemoveExtraWhitespaces.NormalizeWhiteSpace(_text));
Assert.AreEqual(_expected, result);
}
[Test]
public void NormalizeWhiteSpaceForLoop()
{
var result = TimeAction("NormalizeWhiteSpaceForLoop", () => RemoveExtraWhitespaces.NormalizeWhiteSpaceForLoop(_text));
Assert.AreEqual(_expected, result);
}
public string TimeAction(string name, Func<string> func)
{
var timer = Stopwatch.StartNew();
string result = string.Empty; ;
for (int i = 0; i < _iterations; i++)
{
result = func();
}
timer.Stop();
Console.WriteLine(string.Format("{0}: {1} ms", name, timer.ElapsedMilliseconds));
return result;
}
}
string q = " Hello how are you doing?";
string a = String.Join(" ", q.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries));
Нет необходимости в сложном коде! Вот простой код, который удалит любые дубликаты:
public static String RemoveCharOccurence(String s, char[] remove)
{
String s1 = s;
foreach(char c in remove)
{
s1 = RemoveCharOccurence(s1, c);
}
return s1;
}
public static String RemoveCharOccurence(String s, char remove)
{
StringBuilder sb = new StringBuilder(s.Length);
Boolean removeNextIfMatch = false;
foreach(char c in s)
{
if(c == remove)
{
if(removeNextIfMatch)
continue;
else
removeNextIfMatch = true;
}
else
removeNextIfMatch = false;
sb.Append(c);
}
return sb.ToString();
}
В этом вопросе не совсем ясно, какие требования заслуживают.
Это очень эффективная версия, которая заменяет все пробелы одним пространством и удаляет любое начальное и конечное пробелы перед циклом for.
public static string WhiteSpaceToSingleSpaces(string input)
{
if (input.Length < 2)
return input;
StringBuilder sb = new StringBuilder();
input = input.Trim();
char lastChar = input[0];
bool lastCharWhiteSpace = false;
for (int i = 1; i < input.Length; i++)
{
bool whiteSpace = char.IsWhiteSpace(input[i]);
//Skip duplicate whitespace characters
if (whiteSpace && lastCharWhiteSpace)
continue;
//Replace all whitespace with a single space.
if (whiteSpace)
sb.Append(' ');
else
sb.Append(input[i]);
//Keep track of the last character's whitespace status
lastCharWhiteSpace = whiteSpace;
}
return sb.ToString();
}
попробуйте следующее:
System.Text.RegularExpressions.Regex.Replace(input, @"\s+", " ");
Я только что взбила это, но еще не проверила. Но я чувствовал, что это изящно и позволяет избежать регулярного выражения:
/// <summary>
/// Removes extra white space.
/// </summary>
/// <param name="s">
/// The string
/// </param>
/// <returns>
/// The string, with only single white-space groupings.
/// </returns>
public static string RemoveExtraWhiteSpace(this string s)
{
if (s.Length == 0)
{
return string.Empty;
}
var stringBuilder = new StringBuilder();
var whiteSpaceCount = 0;
foreach (var character in s)
{
if (char.IsWhiteSpace(character))
{
whiteSpaceCount++;
}
else
{
whiteSpaceCount = 0;
}
if (whiteSpaceCount > 1)
{
continue;
}
stringBuilder.Append(character);
}
return stringBuilder.ToString();
}
Это очень просто, просто используйте метод .Replace()
:
string words = "Hello world!";
words = words.Replace("\\s+", " ");
Результат >>> «Привет, мир!»
blockquote>
Для тех, кто просто хочет скопировать pase и продолжать:
private string RemoveExcessiveWhitespace(string value)
{
if (value == null) { return null; }
var builder = new StringBuilder();
var ignoreWhitespace = false;
foreach (var c in value)
{
if (!ignoreWhitespace || c != ' ')
{
builder.Append(c);
}
ignoreWhitespace = c == ' ';
}
return builder.ToString();
}
вы можете использовать indexOf для первого захвата, где начинаются последовательности пробелов, а затем использовать метод replace, чтобы изменить пробел на «». Оттуда вы можете использовать индекс, который вы захватили, и поместить один пробельный символ в это место.
Мне понадобился один из них для больших строк и появился подпрограмма ниже.
Любое последовательное белое пространство (включая вкладки, новые строки) заменяется на все, что находится в normalizeTo
. Ведущее / конечное белое пространство удаляется.
Это примерно в 8 раз быстрее, чем RegEx с моими строками char 5k-> 5mil.
internal static string NormalizeWhiteSpace(string input, char normalizeTo = ' ')
{
if (string.IsNullOrEmpty(input))
return string.Empty;
int current = 0;
char[] output = new char[input.Length];
bool skipped = false;
foreach (char c in input.ToCharArray())
{
if (char.IsWhiteSpace(c))
{
if (!skipped)
{
if (current > 0)
output[current++] = normalizeTo;
skipped = true;
}
}
else
{
skipped = false;
output[current++] = c;
}
}
return new string(output, 0, skipped ? current - 1 : current);
}
string text = "foo bar";
text = Regex.Replace(text, @"\s+", " ");
// text = "foo bar"
Это решение работает с пробелами, вкладками и новой строкой. Если вы хотите просто пробелы, замените '\ s' на '..
public static string RemoveExtraSpaces(string input)
{
input = input.Trim();
string output = "";
bool WasLastCharSpace = false;
for (int i = 0; i < input.Length; i++)
{
if (input[i] == ' ' && WasLastCharSpace)
continue;
WasLastCharSpace = input[i] == ' ';
output += input[i];
}
return output;
}
Я использую ниже методы - они обрабатывают все пробельные символы не только пробелами, обрезают как верхние, так и конечные пробелы, удаляют лишние пробелы, а все пробелы заменяются на пробел char (поэтому у нас есть единый разделитель пространства). И эти методы бывают быстрыми.
public static String CompactWhitespaces( String s )
{
StringBuilder sb = new StringBuilder( s );
CompactWhitespaces( sb );
return sb.ToString();
}
public static void CompactWhitespaces( StringBuilder sb )
{
if( sb.Length == 0 )
return;
// set [start] to first not-whitespace char or to sb.Length
int start = 0;
while( start < sb.Length )
{
if( Char.IsWhiteSpace( sb[ start ] ) )
start++;
else
break;
}
// if [sb] has only whitespaces, then return empty string
if( start == sb.Length )
{
sb.Length = 0;
return;
}
// set [end] to last not-whitespace char
int end = sb.Length - 1;
while( end >= 0 )
{
if( Char.IsWhiteSpace( sb[ end ] ) )
end--;
else
break;
}
// compact string
int dest = 0;
bool previousIsWhitespace = false;
for( int i = start; i <= end; i++ )
{
if( Char.IsWhiteSpace( sb[ i ] ) )
{
if( !previousIsWhitespace )
{
previousIsWhitespace = true;
sb[ dest ] = ' ';
dest++;
}
}
else
{
previousIsWhitespace = false;
sb[ dest ] = sb[ i ];
dest++;
}
}
sb.Length = dest;
}
Вы можете использовать регулярное выражение:
static readonly Regex trimmer = new Regex(@"\s\s+");
s = trimmer.Replace(s, " ");
Для повышения производительности передайте RegexOptions.Compiled
.
Это не быстро, но если простота помогает, это работает:
while (text.Contains(" ")) text=text.Replace(" ", " ");
Я что-то упустил? Я придумал это:
// Input: "HELLO BEAUTIFUL WORLD!"
private string NormalizeWhitespace(string inputStr)
{
// First split the string on the spaces but exclude the spaces themselves
// Using the input string the length of the array will be 3. If the spaces
// were not filtered out they would be included in the array
var splitParts = inputStr.Split(' ').Where(x => x != "").ToArray();
// Now iterate over the parts in the array and add them to the return
// string. If the current part is not the last part, add a space after.
for (int i = 0; i < splitParts.Count(); i++)
{
retVal += splitParts[i];
if (i != splitParts.Count() - 1)
{
retVal += " ";
}
}
return retVal;
}
// Would return "HELLO BEAUTIFUL WORLD!"
Я знаю, что создаю вторую строку здесь, чтобы вернуть ее, а также создать массив splitParts. Просто подумал, что это довольно прямолинейно. Возможно, я не учитываю некоторые потенциальные сценарии.
Я попытался использовать StringBuilder для:
Вот лучший баланс производительности & amp; читаемость, которую я нашел (с использованием 100 000 циклов итераций). Иногда это быстрее, чем менее читаемая версия, на 5% медленнее. На моей маленькой тестовой строке регулярное выражение занимает 4,24 раза больше времени.
public static string RemoveExtraWhitespace(string str)
{
var sb = new StringBuilder();
var prevIsWhitespace = false;
foreach (var ch in str)
{
var isWhitespace = char.IsWhiteSpace(ch);
if (prevIsWhitespace && isWhitespace)
{
continue;
}
sb.Append(ch);
prevIsWhitespace = isWhitespace;
}
return sb.ToString();
}
Это смешно, но на моем компьютере метод ниже так же быстро, как и подход StringBulder от Сергея Поваляева - (~ 282 мс за 1000 повторений, строки 10k src). Не уверен в использовании памяти.
string RemoveExtraWhiteSpace(string src, char[] wsChars){
return string.Join(" ",src.Split(wsChars, StringSplitOptions.RemoveEmptyEntries));
}
Очевидно, что все работает хорошо с любыми символами - не просто пробелами.
Хотя это не то, о чем попросил OP, - но если что вы действительно необходимо заменить определенные последовательные символы в строке только одним экземпляром, который вы можете использовать для этого относительно эффективного метода:
string RemoveDuplicateChars(string src, char[] dupes){
var sd = (char[])dupes.Clone();
Array.Sort(sd);
var res = new StringBuilder(src.Length);
for(int i = 0; i<src.Length; i++){
if( i==0 || src[i]!=src[i-1] || Array.BinarySearch(sd,src[i])<0){
res.Append(src[i]);
}
}
return res.ToString();
}