我有C#字符串,其中包含句子。有时候这些句子都可以,有时它们只是用户生成的随机字符。我想做的是修剪这些句子中的单词。例如,给出以下字符串:
var stringWithLongWords = "Here's a text with tooooooooooooo long words";
我想通过过滤器运行:
var trimmed = TrimLongWords(stringWithLongWords, 6);
并获得一个输出,其中每个单词最多只能包含6个字符:
"Here's a text with tooooo long words"
有什么想法可以通过良好的表现来实现这一目标吗? .NET中有什么可以自动处理的吗?
我目前正在使用以下代码:
private static string TrimLongWords(string original, int maxCount)
{
return string.Join(" ", original.Split(' ').Select(x => x.Substring(0, x.Length > maxCount ? maxCount : x.Length)));
}
理论上有效,但如果长词以空格之外的分隔符结尾,则会提供错误的输出。例如:
这是sweeeeeeeeeeeeeeeetet!还有更多。
看起来像这样:
这是sweeeeeeee等等。
更新:
好的,评论非常好,我意识到这可能有太多“假设”。如果忘记分隔符也许会更好。相反,如果一个单词被修剪,它可以用三个点显示。以下是一些修剪为最多5个字符的示例:
天启现在! - >阿波卡......现在!
启示! - > Apoca ...
!例! - > !考试......
这是sweeeeeeeeeeeeeeeetet!还有更多。 - >这太好了......还有一些......更多。
答案 0 :(得分:4)
编辑:由于要求已经改变,我将保持精神与正则表达式:
Regex.Replace(original, string.Format(@"(\p{{L}}{{{0}}})\p{{L}}+", maxLength), "$1...");
输出 maxLength = 6:
Here's a text with tooooo... long words
This is sweeee...! And someth... more.
下面的老答案,因为我喜欢这种方法,即使它有点......凌乱: - )。
我将一个小的正则表达式替换为了这样做。它现在在PowerShell中(用于原型设计;之后我将转换为C#):
'Here''s a text with tooooooooooooo long words','This is sweeeeeeeeeeeeeeeet! And something more.' |
% {
[Regex]::Replace($_, '(\w*?)(\w)\2{2,}(\w*)',
{
$m = $args[0]
if ($m.Value.Length -gt 6) {
$l = 6 - $m.Groups[1].Length - $m.Groups[3].Length
$m.Groups[1].Value + $m.Groups[2].Value * $l + $m.Groups[3].Value
}
})
}
输出是:
Here's a text with tooooo long words
This is sweeet! And something more.
这样做的目的是找到符合\w
模式的字符(现在(something)(repeated character more than two times)(something else)
;应该更改为合理的字符串)。对于替换,它使用一个函数来检查它的长度是否超过所需的最大长度,然后它计算重复部分实际上仍然适合总长度的时间长度,然后仅将重复部分减少到该长度。
太乱了。它将无法截断非常长的单词(例如第二个测试句中的“某些东西”),并且构成单词的字符集也需要更改。如果您想要走这条路线,那么这可能是一个起点,但不是一个完整的解决方案。
C#代码:
public static string TrimLongWords(this string original, int maxCount)
{
return Regex.Replace(original, @"(\w*?)(\w)\2{2,}(\w*)",
delegate(Match m) {
var first = m.Groups[0].Value;
var rep = m.Groups[1].Value;
var last = m.Groups[2].Value;
if (m.Value.Length > maxCount) {
var l = maxCount - first.Length - last.Length;
return first + new string(rep[0], l) + last;
}
return m.Value;
});
}
根据您的需要,字符类的更好选项可能类似于\p{L}
。
答案 1 :(得分:4)
我建议使用StringBuilder
和循环:
public string TrimLongWords(string input, int maxWordLength)
{
StringBuilder sb = new StringBuilder(input.Length);
int currentWordLength = 0;
bool stopTripleDot = false;
foreach (char c in input)
{
bool isLetter = char.IsLetter(c);
if (currentWordLength < maxWordLength || !isLetter)
{
sb.Append(c);
stopTripleDot = false;
if (isLetter)
currentWordLength++;
else
currentWordLength = 0;
}
else if (!stopTripleDot)
{
sb.Append("...");
stopTripleDot = true;
}
}
return sb.ToString();
}
这比Regex
或Linq更快
maxWordLength == 6
的预期结果:
"UltraLongWord" -> "UltraL..."
"This-is-not-a-long-word" -> "This-is-not-a-long-word"
边缘案例maxWordLength == 0
会导致:
"Please don't trim me!!!" -> "... ...'... ... ...!!!" // poor, poor string...
"..."
] (我刚刚意识到用"..."
替换修剪过的子串已经引入了很多错误,修复它们会让我的代码变得有点笨重,抱歉)
答案 2 :(得分:2)
试试这个:
private static string TrimLongWords(string original, int maxCount)
{
return string.Join(" ",
original.Split(' ')
.Select(x => {
var r = Regex.Replace(x, @"\W", "");
return r.Substring(0, r.Length > maxCount ? maxCount : r.Length) + Regex.Replace(x, @"\w", "");
}));
}
然后TrimLongWords("This is sweeeeeeeeeeeeeeeet! And something more.", 5)
变为"This is sweee! And somet more."
答案 3 :(得分:2)
这比正则表达式或Linq方法更有效。但是,它不会按字词分割或添加...
。白色空间(包括换行符或制表符)也应缩短。
public static string TrimLongWords(string original, int maxCount)
{
if (null == original || original.Length <= maxCount) return original;
StringBuilder builder = new StringBuilder(original.Length);
int occurence = 0;
for (int i = 0; i < original.Length; i++)
{
Char current = original[i];
if (current == original.ElementAtOrDefault(i-1))
occurence++;
else
occurence = 1;
if (occurence <= maxCount)
builder.Append(current);
}
return builder.ToString();
}
答案 4 :(得分:2)
您可以使用正则表达式来查找重复内容:
string test = "This is sweeeeeeeeeeeeeeeet! And sooooooomething more.";
string result = Regex.Replace(test, @"(\w)\1+", delegate(Match match)
{
string v = match.ToString();
return v[0].ToString();
});
结果将是:
This is swet! And something more.
也许你可以用拼写检查服务检查操纵的单词: http://wiki.webspellchecker.net/doku.php?id=installationandconfiguration:web_service
答案 5 :(得分:2)
试试这个:
class Program
{
static void Main(string[] args)
{
var stringWithLongWords = "Here's a text with tooooooooooooo long words";
var trimmed = TrimLongWords(stringWithLongWords, 6);
}
private static string TrimLongWords(string stringWithLongWords, int p)
{
return Regex.Replace(stringWithLongWords, String.Format(@"[\w]{{{0},}}", p), m =>
{
return m.Value.Substring(0, p-1) + "...";
});
}
}
答案 6 :(得分:2)
使用带有零宽度正向后置断言的简单正则表达式(LinqPad - 就绪示例代码):
void Main()
{
foreach(var s in new [] { "Here's a text with tooooooooooooo long words",
"This is sweeeeeeeeeeeeeeeet! And something more.",
"Apocalypse now!",
"Apocalypse!",
"!Example!"})
Regex.Replace(s, @"(?<=\w{5,})\S+", "...").Dump();
}
它会查找5个字符后面的任何非空格字符,并将匹配替换为...
。
结果:
这是一个太长的文字......长话词 这很好......而且有些......更多 阿波卡......现在!
Apoca ...
!例子......
答案 7 :(得分:2)
@Curt在评论中建议采用更实用的方法。
我无法立即想到任何包含3个相同字母的英文单词。您可以尝试这种方法,而不是简单地删除6个字符后的单词:每当您连续两次遇到相同的字符时,请删除它的任何其他连续出现。因此,“sweeeeeet”变得“甜蜜”,“tooooooo”变得“太”。
这会产生额外的副作用,即将相同标点符号或空白区域的数量限制为2,以防有人过于热心于那些!!!!!!!!
如果您想考虑省略号(...),那么只需将“最大连续字符数”计算为== 3,而不是2。
答案 8 :(得分:1)
以下将重复字符的数量限制为6.因此,对于您的输入“这是sweeeeeeeeeeeeeeeet!还有更多内容。”输出将是:
“这是sweeeeeet!还有更多。”
string s = "heloooooooooooooooooooooo worrrllllllllllllld!";
char[] chr = s.ToCharArray();
StringBuilder sb = new StringBuilder();
char currentchar = new char();
int charCount = 0;
foreach (char c in chr)
{
if (c == currentchar)
{
charCount++;
}
else
{
charCount = 0;
}
if ( charCount < 6)
{
sb.Append(c);
}
currentchar = c;
}
Console.WriteLine(sb.ToString());
//Output heloooooo worrrlllllld!
编辑:截断超过6个字符的字词:
string s = "This is sweeeeeeeeeeeeeeeet! And something more.";
string[] words = s.Split(' ');
StringBuilder sb = new StringBuilder();
foreach (string word in words)
{
char[] chars = word.ToCharArray();
if (chars.Length > 6)
{
for (int i = 0; i < 6; i++)
{
sb.Append(chars[i]);
}
sb.Append("...").Append(" ");
}
else { sb.Append(word).Append(" "); }
}
sb.Remove(sb.Length - 1, 1);
Console.WriteLine(sb.ToString());
//Output: "This is sweeee... And someth... more."