C#和VB.NET中的字符串处理对我来说很容易,但是理解如何在F#中做同样的事情并不那么容易.我正在读两本Apress F#书(基础和专家).大多数样本都是数字运算,而且我认为,字符串操作很少.特别是,seq {sequence-expression}和Lists的样本.
我有一个C#程序,我想转换为F#.这是它的作用:
这是一个简单的例子,说明我在C#中可以做什么,但在F#中还没有.
假设这是一个文本文件:
命令,最高法院,纽约县(Paul G Someone),于2008年3月18日进入,该行为因旅行中遭受的人身伤害而摔倒,据称由于被告城市或联合麦克弗森的疏忽造成了坑洼,联合麦克弗森对其承包商(Mallen)提起的第三方诉讼,就其上诉而言,否认,不合时宜,Mallen的简易判决动议驳回了投诉和第三方投诉,一致肯定,没有任何费用.
通过法院,规定或其他方式,各方可以自由地规划其程序性过程.因此,我们肯定否认Mallen的动议是不合时宜的,因为Mallen没有为迟到的申请提供借口.
我得到这个输出:
2 Paragraphs
3 Lines
109 Words
Found Tokens: 2
Token insofar: ocurrence(s) 1: position(s): 52
Token thus: ocurrence(s) 1: position(s): 91
Run Code Online (Sandbox Code Playgroud)
行应该被称为句子:(
有几个令牌.我会说超过100个按类分组.我必须多次迭代同一文本,试图匹配每个令牌.这是代码的一部分.它显示了我如何分割句子,将它们放在ListBox中,这有助于轻松获取项目数.这适用于段落,句子和标记.它还显示了我依赖和预测的方式.我希望通过使用seq {sequence-expression}和Lists和seq.iter或List.iter以及任何匹配令牌来避免使用这种方法.
/// <summary>
/// split the text into sentences and displays
/// the results in a list box
/// </summary>
private void btnParseText_Click(object sender, EventArgs e)
{
lstLines.Items.Clear();
ArrayList al = SplitLines(richTextBoxParagraphs.Text);
for (int i = 0; i < al.Count; i++)
//populate a list box
lstLines.Items.Add(al[i].ToString());
}
/// <summary>
/// parse a body of text into sentences
/// </summary>
private ArrayList SplitLines(string sText)
{
// array list tto hold the sentences
ArrayList al = new ArrayList();
// split the lines regexp
string[] splitLines =
Regex.Split(sText, @"(?<=['""A-Za-z0-9][\.\!\?])\s+(?=[A-Z])");
// loop the sentences
for (int i = 0; i < splitLines.Length; i++)
{
string sOneLine =
splitLines[i].Replace(Environment.NewLine, string.Empty);
al.Add(sOneLine.Trim());
}
// update statistics
lblLineCount.Text = "Line Count: " +
GetLineCount(splitLines).ToString();
// words
lblWordCount.Text = "Word Count: " +
GetWordCount(al).ToString();
// tokens
lblTokenCount.Text = "Token Count: " +
GetTokenCount(al).ToString();
// return the arraylist
return al;
}
/// <summary>
/// count of all words contained in the ArrayList
/// </summary>
public int GetWordCount(ArrayList allLines)
{
// return value
int rtn = 0;
// iterate through list
foreach (string sLine in allLines)
{
// empty space is the split char
char[] arrSplitChars = {' '};
// create a string array and populate
string[] arrWords = sSentence.Split(arrSplitChars, StringSplitOptions.RemoveEmptyEntries);
rtn += arrWords.Length;
}
// return word count
return rtn;
}
Run Code Online (Sandbox Code Playgroud)
实际上,它是一个非常简单的Windows应用程序.包含一个RichTextBox和三个ListBox(已找到段落,行,标记)的表单,用于显示输出的标签和一个按钮.
Brian有一个良好的开端,但功能代码将更多地关注你正在尝试做什么而不是"如何".
我们可以从类似的方式开始:
open System
open System.Text.RegularExpressions
let text = @"Order, Supreme Court, New York County (Paul G Someone), entered..."
let lines = text.Split([|Environment.NewLine|], StringSplitOptions.None)
Run Code Online (Sandbox Code Playgroud)
首先,让我们看看段落.我喜欢Brian的方法来计算分隔段落的空行.所以我们过滤只查找空行,计算它们,然后根据该值返回我们的段落计数:
let numParagraphs =
let blankLines = lines |> Seq.filter (fun line -> Regex.IsMatch(line, @"^\s*$"))
|> Seq.length
blankLines + 1
Run Code Online (Sandbox Code Playgroud)
对于句子,我们可以将全文视为一系列字符并计算句子结尾字符的数量.因为它是F#,让我们使用模式匹配:
let numSentences =
let isSentenceEndChar c = match c with
| '.' | '!' | '?' -> true
| _ -> false
text |> Seq.filter isSentenceEndChar
|> Seq.length
Run Code Online (Sandbox Code Playgroud)
匹配单词可以像简单的正则表达式一样简单,但可能会随着你想要处理标点符号的方式而变化:
let words = Regex.Split(text, "\s+")
let numWords = words.Length
numParagraphs |> printfn "%d paragraphs"
numSentences |> printfn "%d sentences"
numWords |> printfn "%d words"
Run Code Online (Sandbox Code Playgroud)
最后,我们定义了一个打印令牌出现的函数,可以很容易地应用于令牌列表:
let findToken token =
let tokenMatch (word : string) = word.Equals(token, StringComparison.OrdinalIgnoreCase)
words |> Seq.iteri (fun n word ->
if tokenMatch word then
printfn "Found %s at word %d" word n
)
let tokensToFind = ["insofar"; "thus"; "the"]
tokensToFind |> Seq.iter findToken
Run Code Online (Sandbox Code Playgroud)
请注意,由于其尾随逗号,此代码找不到"因此".您可能希望调整words生成方式或tokenMatch定义方式.