Ответ 1
String.Split() (без параметров) разделяет на все пробелы (включая LF/CR)
Мне нужно разбить строку во всех пробелах, она должна ТОЛЬКО содержать сами слова.
Как это сделать в vb.net?
Вкладки, Newlines и т.д. должны быть разделены!
Это уже давно подтачивало меня, поскольку мой синтаксический ярлык я полностью игнорировал первое слово в каждой строке, кроме самой первой строки.
String.Split() (без параметров) разделяет на все пробелы (включая LF/CR)
Попробуйте следующее:
Regex.Split("your string here", "\s+")
Если вы хотите избежать регулярных выражений, вы можете сделать это следующим образом:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit"
.Split()
.Where(x => x != string.Empty)
Visual Basic эквивалент:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit" _
.Split() _
.Where(Function(X$) X <> String.Empty)
Функция Where()
важна, поскольку, если ваша строка содержит несколько пробелов рядом друг с другом, она удаляет пустые строки, которые появятся в результате Split()
.
На момент написания, принятый в настоящее время ответ (fooobar.com/questions/37786/...) не учитывает это.
String.Split()
будет разделяться на каждое одиночное пробелы, поэтому результат будет содержать пустые строки. Решение Regex, предложенное Рубеном Фариасом, является правильным способом сделать это. Я поддержал его ответ, но я хочу дать небольшое дополнение, рассекая регулярное выражение:
\s
является класс символов, который соответствует всем пробельным символам.
Чтобы правильно разбить строку, когда она содержит несколько пробельных символов между словами, нам нужно добавить quantifier (или оператор повторения) к спецификации, чтобы соответствовать всем пробелам между словами. В этом случае правильным квантором является +
, что означает "одно или несколько" вхождений данной спецификации. Хотя синтаксиса "\s+"
здесь достаточно, я предпочитаю более явный "[\s]+
".
Итак, увидев пост Адама Ральфа, я подозревал, что его решение было быстрее, чем решение Regex. Просто подумал, что я поделюсь результатами моего тестирования, так как нашел, что это было быстрее.
В игре действительно действуют два фактора (игнорируя системные переменные): количество выделенных подстрок (определяется количеством разделителей) и общая длина строки. Самый простой сценарий, построенный ниже, использует "A" в качестве подстроки, разделенной двумя пробелами (пробел, за которым следует вкладка). Это подчеркивает влияние количества выделенных подстрок. Я пошел дальше и сделал несколько тестов с несколькими переменными, чтобы получить следующие общие уравнения для моей операционной системы.
Regex()
t = (28,33 * SSL + 572) (SSN/10 ^ 6)
Split(). Где()
t = (6.23 * SSL + 250) (SSN/10 ^ 6)
Где t - время выполнения в миллисекундах, SSL - средняя длина подстроки, а SSN - количество подстрок, разделенных строкой.
Эти уравнения также могут быть записаны как
t = (28.33 * SL + 572 * SSN)/10 ^ 6
и
t = (6.23 * SL + 250 * SSN)/10 ^ 6
где SL - общая длина строки (SL = SSL * SSN)
Вывод: Решение Split(). Where() быстрее, чем Regex(). Основным фактором является количество подстрок, а длина строки играет второстепенную роль. Производительность составляет около 2x и 5x для соответствующих коэффициентов.
Здесь мой тестовый код (возможно, более материал, чем необходимо, но он настроен для получения данных с несколькими переменными, о которых я говорил)
using System;
using System.Linq;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace ConsoleApplication1
{
class Program
{
public enum TestMethods {regex, split};
[STAThread]
static void Main(string[] args)
{
//Compare TestMethod execution times and output result information
//to the console at runtime and to the clipboard at program finish (so that data is ready to paste into analysis environment)
#region Config_Variables
//Choose test method from TestMethods enumerator (regex or split)
TestMethods TestMethod = TestMethods.split;
//Configure RepetitionString
String RepetitionString = string.Join(" \t", Enumerable.Repeat("A",100));
//Configure initial and maximum count of string repetitions (final count may not equal max)
int RepCountInitial = 100;int RepCountMax = 1000 * 100;
//Step increment to next RepCount (calculated as 20% increase from current value)
Func<int, int> Step = x => (int)Math.Round(x / 5.0, 0);
//Execution count used to determine average speed (calculated to adjust down to 1 execution at long execution times)
Func<double, int> ExecutionCount = x => (int)(1 + Math.Round(500.0 / (x + 1), 0));
#endregion
#region NonConfig_Variables
string s;
string Results = "";
string ResultInfo;
double ResultTime = 1;
#endregion
for (int RepCount = RepCountInitial; RepCount < RepCountMax; RepCount += Step(RepCount))
{
s = string.Join("", Enumerable.Repeat(RepetitionString, RepCount));
ResultTime = Test(s, ExecutionCount(ResultTime), TestMethod);
ResultInfo = ResultTime.ToString() + "\t" + RepCount.ToString() + "\t" + ExecutionCount(ResultTime).ToString() + "\t" + TestMethod.ToString();
Console.WriteLine(ResultInfo);
Results += ResultInfo + "\r\n";
}
Clipboard.SetText(Results);
}
public static double Test(string s, int iMax, TestMethods Method)
{
switch (Method)
{
case TestMethods.regex:
return Math.Round(RegexRunTime(s, iMax),2);
case TestMethods.split:
return Math.Round(SplitRunTime(s, iMax),2);
default:
return -1;
}
}
private static double RegexRunTime(string s, int iMax)
{
Stopwatch sw = new Stopwatch();
sw.Restart();
for (int i = 0; i < iMax; i++)
{
System.Collections.Generic.IEnumerable<string> ens = Regex.Split(s, @"\s+");
}
sw.Stop();
return Math.Round(sw.ElapsedMilliseconds / (double)iMax, 2);
}
private static double SplitRunTime(string s,int iMax)
{
Stopwatch sw = new Stopwatch();
sw.Restart();
for (int i = 0; i < iMax; i++)
{
System.Collections.Generic.IEnumerable<string> ens = s.Split().Where(x => x != string.Empty);
}
sw.Stop();
return Math.Round(sw.ElapsedMilliseconds / (double)iMax, 2);
}
}
}
Я нашел, что использовал решение, как заметил Адам Ральф, плюс комментарий VB.NET ниже на P57, но с одним странным исключением. Я обнаружил, что в конце должен был добавить .ToList.ToArray.
Так же:
.Split().Where(Function(x) x <> String.Empty).ToList.ToArray
Без этого я продолжал получать "Невозможно передать объект типа" WhereArrayIterator`1 [System.String] "для ввода" System.String [] ".
Dim words As String = "This is a list of words, with: a bit of punctuation" + _
vbTab + "and a tab character." + vbNewLine
Dim split As String() = words.Split(New [Char]() {" "c, CChar(vbTab), CChar(vbNewLine) })