C# 将列表转换为带有元音和结尾“and”的字符串
我正试图从列表中创建一个字符串。然而,我希望它被安排在一个有意义的方式,因此,我没有线是苹果,香蕉,爸爸的柑橘,我希望它是我有一个苹果,香蕉,和爸爸的柑橘。。绳子是苹果、香蕉和爸爸的柑橘 我宁愿不改变构成我的列表的字符串;我正在研究的是一个mod,它会根据其他mod的启用情况更改列表,因此在每个组的最后一个字符串中添加“and”不会很好 总之,我想要的代码将列表转换为字符串,在以辅音开头的单词前面添加“a”,在带元音的单词前面添加“an”,在带撇号的单词前面都不添加C# 将列表转换为带有元音和结尾“and”的字符串,c#,C#,我正试图从列表中创建一个字符串。然而,我希望它被安排在一个有意义的方式,因此,我没有线是苹果,香蕉,爸爸的柑橘,我希望它是我有一个苹果,香蕉,和爸爸的柑橘。。绳子是苹果、香蕉和爸爸的柑橘 我宁愿不改变构成我的列表的字符串;我正在研究的是一个mod,它会根据其他mod的启用情况更改列表,因此在每个组的最后一个字符串中添加“and”不会很好 总之,我想要的代码将列表转换为字符串,在以辅音开头的单词前面添加“a”,在带元音的单词前面添加“an”,在带撇号的单词前面都不添加 谢谢 不清楚您的输入是什么样
谢谢 不清楚您的输入是什么样子的,但它可能类似于这个控制台应用程序。然而,英语不是我的第一语言,所以我可能大错特错:
static void Main(string[] args)
{
List<string> strings = new List<string>
{
"apple",
"banana",
"Papa's citrus"
};
var lastNdx = strings.Count - 1;
var sentence = "I have " + String.Join(", ",
strings.Select((s, ndx) =>
{
var ls = s.ToLower();
string ret = "";
if ("aeiou".Contains(ls[0]))
ret = "an " + s;
else if (ls.Contains("\'"))
ret = s;
else ret = "a " + s;
if (ndx == lastNdx)
ret = "and " + ret;
return ret;
}).ToArray() );
Console.WriteLine(sentence);
}
使用一些方便的扩展方法:
public static class IEnumerableExt {
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source) => new HashSet<T>(source);
public static IEnumerable<T> Leave<T>(this ICollection<T> src, int drop) => src.Take(src.Count - drop);
public static IEnumerable<T> Drop<T>(this ICollection<T> src, int drop) => (drop < 0) ? src.Leave(-drop) : src.Skip(drop);
}
public static class StringExt {
public static string UpTo(this string s, Regex stopRE) {
var m = stopRE.Match(s);
if (m.Success)
return s.Substring(0, m.Index);
else
return s;
}
public static string Join(this IEnumerable<string> strings, string sep) => String.Join(sep, strings.ToArray());
public static bool EndsWithOneOf(this string s, params string[] endings) => endings.Any(e => s.EndsWith(e));
}
Drop和Last在一般情况下并不是特别有效,但因为我们知道我们使用的是列表,所以它们很好,而且不管怎样数据都很短。这个答案是针对@Stillgar的。这有点复杂,所以我做了第二个答案 下载的最新版本并将其存储在文件夹中。在CMUDictExt类中设置使用该文件夹的路径:
public static class CMUDictExt {
const string cmuFolder = @"D:\";
static IEnumerable<string> CMUFiles = Directory.EnumerateFiles(cmuFolder, "cmudict-*");
static Regex cmudictName = new Regex(@"cmudict-(?:\d+(?:\.\d+)?[a-z]?)+\.?(.*)$", RegexOptions.Compiled);
static string CMUFile(string ext) => CMUFiles.First(f => cmudictName.Match(f).Groups[1].Value == ext);
static Dictionary<string, string> phones;
static Dictionary<string, string[]> pronunciations;
public static ILookup<string, string> SymbolWords;
static HashSet<string> exceptions;
static CMUDictExt() {
phones = File.ReadLines(CMUFile("phones"))
.Select(l => l.Split('\t'))
.ToDictionary(pa => pa[0], pa => pa[1]);
pronunciations = File.ReadLines(CMUFile(""))
.Where(l => !l.StartsWith(";;;"))
.Where(l => Char.IsLetter(l[0]))
.Select(l => l.Split(" ").ToArray())
.ToDictionary(wg => wg[0].ToLowerInvariant(), wg => wg[1].Split(' '));
SymbolWords = pronunciations.SelectMany(wp => wp.Value.Select(s => (Word: wp.Key, s)))
.ToLookup(wp => wp.s, wp => wp.Word);
exceptions = pronunciations.Where(wp => (wp.Key.StartsWithVowel() ^ wp.Value[0].Phone() == "vowel")).Select(wp => wp.Key).ToHashSet();
}
public static string Phone(this string aSymbol) => phones.GetValueOrDefault(aSymbol.UpTo(ch => Char.IsDigit(ch)), String.Empty);
static string[] emptyStringArray = new string[] {};
public static string[] Pronunciation(this string aWord) => pronunciations.GetValueOrDefault(aWord.ToLowerInvariant(), emptyStringArray);
public static bool HasPronunciation(this string aWord) => pronunciations.GetValueOrDefault(aWord.ToLowerInvariant(), null) != null;
static readonly HashSet<char> vowels = "aeiou".ToHashSet<char>();
public static bool StartsWithVowel(this string w) => vowels.Contains(w[0]);
public static bool BeginsWithVowelSound(this string aWord) => exceptions.Contains(aWord) ? !aWord.StartsWithVowel() : aWord.StartsWithVowel(); // guess if not found
}
现在,答案的计算与之前相同,但在默认检查元音之前,它会正确处理许多英语语言异常:
var ans = ("I have " + src.Drop(-1).Select(w => w.ArticleOrPossessive()).Join(", ") + " and " + src.Last().ArticleOrPossessive() + ".");
样本输出:
I have an apple, a banana, Papa's citrus, an honest judge, a highchair, a university and an understanding.
总之,我想要的代码是。。。这对于堆栈溢出来说太宽了。当你无法前进时,你需要自己尝试并提出一个问题,在这里发布代码,这样我们就可以指导你,你已经尝试了什么?@Stilgar我就是这么想的。问题太广泛了,因为OP还没有尝试过任何东西,所以它不是一个代码编写服务。随机尝试正是应该做的。没有人说这个问题质量不高,只是说它不适合这里。@Stillgar所以你认为这个问题表明了研究的努力?@Screerdasnek你仍然可以改进你的问题,这就是我们在这里的最终目标:如果他的字符串中允许使用形容词,那么该方法不正确的单词数量会增加很多。@Stilgar怎么会这样呢?红苹果和橘子一样有效,不是吗?比如诚实vshigh@Stilgar我为你添加了一个答案:现在更像是这样了@Stillgar添加了一些示例输出,并对其进行了一点改进。顺便说一句,我不需要这个,只是好奇什么是合适的解决方案:@Stillgar Me,也是:
public static class IEnumerableExt {
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source) => new HashSet<T>(source);
public static IEnumerable<T> Leave<T>(this ICollection<T> src, int drop) => src.Take(src.Count - drop);
public static IEnumerable<T> Drop<T>(this ICollection<T> src, int drop) => (drop < 0) ? src.Leave(-drop) : src.Skip(drop);
public static T MinBy<T, TKey>(this IEnumerable<T> src, Func<T, TKey> keySelector, Comparer<TKey> keyComparer) => src.Aggregate((a, b) => keyComparer.Compare(keySelector(a), keySelector(b)) < 0 ? a : b);
public static T MinBy<T, TKey>(this IEnumerable<T> src, Func<T, TKey> keySelector) => src.Aggregate((a, b) => Comparer<TKey>.Default.Compare(keySelector(a), keySelector(b)) < 0 ? a : b);
}
public static class StringExt {
public static string UpTo(this string s, Regex stopRE) {
var m = stopRE.Match(s);
if (m.Success)
return s.Substring(0, m.Index);
else
return s;
}
public static string UpTo(this string s, Func<char, bool> testfn) {
var m = s.Select((ch, Index) => new { ch, Index, Success = testfn(ch) }).FirstOrDefault(cit => cit.Success);
if (m != null && m.Success)
return s.Substring(0, m.Index);
else
return s;
}
public static string Join(this IEnumerable<string> strings, string sep) => String.Join(sep, strings.ToArray());
public static bool EndsWithOneOf(this string s, params string[] endings) => endings.Any(e => s.EndsWith(e));
public static IEnumerable<string> Split(this string s, params string[] seps) => s.Split(StringSplitOptions.None, seps);
public static IEnumerable<string> Split(this string s, StringSplitOptions so, params string[] seps) {
int pos = 0;
do {
var sepPos = seps.Select(sep => new { pos = s.IndexOf(sep, pos) < 0 ? s.Length : s.IndexOf(sep, pos), len = sep.Length }).MinBy(pl => pl.pos);
if (sepPos.pos > pos || so == StringSplitOptions.None)
yield return s.Substring(pos, sepPos.pos - pos);
pos = sepPos.pos + sepPos.len;
} while (pos <= s.Length);
}
public static string FirstWord(this string phrase) => phrase.UpTo(ch => Char.IsWhiteSpace(ch));
public static bool IsAllLetters(this string s) => s.All(ch => Char.IsLetter(ch)); // faster than Regex
}
public static class DictionaryExt {
public static TV GetValueOrDefault<TK, TV>(this IDictionary<TK, TV> dict, TK key, TV defaultValue) => dict.TryGetValue(key, out TV value) ? value : defaultValue;
}
public static class FruitExt {
public static bool IsPossessive(this string phrase) => phrase.FirstWord().EndsWithOneOf("'s", "'");
public static string WithIndefiniteArticle(this string phrase) => (phrase.FirstWord().BeginsWithVowelSound() ? "an " : "a ") + phrase;
public static string ArticleOrPossessive(this string phrase) => phrase.IsPossessive() ? phrase : phrase.WithIndefiniteArticle();
}
var ans = ("I have " + src.Drop(-1).Select(w => w.ArticleOrPossessive()).Join(", ") + " and " + src.Last().ArticleOrPossessive() + ".");
I have an apple, a banana, Papa's citrus, an honest judge, a highchair, a university and an understanding.