【问题标题】:How do I split up a search string to allow for quoted text?如何拆分搜索字符串以允许引用文本?
【发布时间】:2011-04-21 17:55:33
【问题描述】:

我想从搜索字段的文本中创建一个字符串列表。 我想将双引号中的任何内容分开。

例如
sample' "string's are, more "text" making" 12.34,hello"pineapple sundays

生产

sample' 
string's are, more_  //underscore shown to display space
text
 making
12.34
hello
pineapple
sundays

编辑:这是我(有点)优雅的解决方案,感谢大家的帮助!

Private Function GetSearchTerms(ByVal searchText As String) As String()
    'Clean search string of unwanted characters'
    searchText = System.Text.RegularExpressions.Regex.Replace(searchText, "[^a-zA-Z0-9""'.,= ]", "")

    'Guarantees the first entry will not be an entry in quotes if the searchkeywords starts with double quotes'
    Dim searches As String() = searchText.Replace("""", " "" ").Split("""")
    Dim myWords As System.Collections.Generic.List(Of String) = New System.Collections.Generic.List(Of String)
    Dim delimiters As String() = New String() {" ", ","}

    For index As Integer = 0 To searches.Length - 1
        'even is regular text, split up into individual search terms'
        If (index Mod 2 = 0) Then
            myWords.AddRange(searches(index).Split(delimiters, StringSplitOptions.RemoveEmptyEntries))
        Else
            'check for unclosed double quote, if so, split it up and add, space we added earlier will get split out'
            If (searches.Length Mod 2 = 0 And index = searches.Length - 1) Then
                myWords.AddRange(searches(index).Split(delimiters, StringSplitOptions.RemoveEmptyEntries))
            Else
                '2 double quotes found'
                'remove the 2 spaces that we added earlier'
                Dim myQuotedString As String = searches(index).Substring(1, searches(index).Length - 2)
                If (myQuotedString.Length > 0) Then
                    myWords.Add(myQuotedString)
                End If
            End If
        End If
    Next
    Return myWords.ToArray()
End Function

哎,vb 评论太丑了,有人知道怎么清理吗?

【问题讨论】:

  • 我的示例字符串中有 5 个引号。我想忽略最后一个没有相应结束引号的。
  • 我将在引号之外的所有内容上拆分空格和逗号。
  • 如果你这样做要小心,因为如果你基于两个字符分割,有时分割函数实际上会分割字符串两次,一次在第一个字符,第二次在第二个字符,这意味着你会得到中间有一行空白数据。

标签: c# .net regex vb.net


【解决方案1】:

这是一个比您完全理解的更复杂的解析问题。我建议你看看 TextFieldParser 类和 FileHelpers 库:http://www.filehelpers.com/

【讨论】:

  • Jim 是一个非常棒的资源,谢谢分享,星期一我会用!
  • 感谢资源,但我不能在此项目中拥有外部库。
【解决方案2】:

这不是完整的解决方案,因为它缺少一些验证检查,但它拥有您需要的一切。

My CharOccurs() 查找出现的 '"' 并将它们按顺序存储到列表中。

public static List<int> CharOccurs(string stringToSearch, char charToFind)
        {
            List<int> count = new List<int>();
            int  chr = 0;
            while (chr != -1)
            {
                chr = stringToSearch.IndexOf(charToFind, chr);
                if (chr != -1)
                {
                    count.Add(chr);
                    chr++;
                }
                else
                {
                    chr = -1;
                }
            }
            return count;
        }

下面的代码本身就是解释性的。我采用引号内的字符串并仅使用'"' character 将它们分开。然后我对外部引号字符串执行 SubStrings 并将它们拆分为 ",", space and '"' 字符。请在需要的地方添加您的验证检查以使其通用。

string input = "sample' \"string's are, more \"text\" making\" 12.34,hello\"pineapple sundays";

            List<int> positions = CharOccurs(input, '\"');

            string within_quotes, outside_quotes;
            string[] arr_within_quotes;
            List<string> output = new List<string>();

            output.AddRange(input.Substring(0, positions[0]-1).Split(new char[] { ' ', ',', '"' }));

            if (positions.Count % 2 == 0)
            {
                within_quotes = input.Substring(positions[0]+1, positions[positions.Count - 1] - positions[0]-1);
                arr_within_quotes = within_quotes.Split('"');
                output.AddRange(arr_within_quotes);
                output.AddRange(input.Substring(positions[positions.Count - 1] + 1).Split(new char[] { ' ', ',' }));
            }
            else
            {
                within_quotes = input.Substring(positions[0]+1, positions[positions.Count - 2] - positions[0]-1);
                arr_within_quotes = within_quotes.Split('"');
                output.AddRange(arr_within_quotes);
                output.AddRange(input.Substring(positions[positions.Count - 2] + 1).Split(new char[] { ' ', ',', '"' }));
            }

【讨论】:

  • 我在第一次通过时就理解了这个解决方案。感谢您的帮助。
【解决方案3】:

几个月前我为 VB.NET 编写了这个 Parse Line 函数,它可能对你有一些用处,它是否存在文本限定符并将根据文本进行拆分,我尝试将其转换为 C#如果你想要我的话,在接下来的几分钟内给你。

你会有你的文本行:

sample' "string's are, more "text" making" 12.34,hello"pineapple sundays

你会把它作为你的 strLine 你会设置你的 strDataDelimers = "," 你会设置你 strTextQualifier = """"

希望对你有所帮助。

Public Function ParseLine(ByVal strLine As String, Optional ByVal strDataDelimiter As String = "", Optional ByVal strTextQualifier As String = "", Optional ByVal strQualifierSplitter As Char = vbTab) As String()
        Try
            Dim strField As String = Nothing
            Dim strNewLine As String = Nothing
            Dim lngChrPos As Integer = 0
            Dim bUseQualifier As Boolean = False
            Dim bRemobedLastDel As Boolean = False
            Dim bEmptyLast As Boolean = False   ' Take into account where the line ends in a field delimiter, the ParseLine function should keep that empty field as well.


            Dim strList As String()

            'TEST,23479234,Just Right 950g,02/04/2006,1234,5678,9999,0000
            'TEST,23479234,Just Right 950g,02/04/2006,1234,5678,9999,0000,
            'TEST,23479234,Just Right 950g,02/04/2006,1234,,,0000,
            'TEST,23479234,Just Right 950g,02/04/2006,1234,5678,9999,,
            'TEST,23479234,"Just Right 950g, BO",02/04/2006,,5678,9999,,
            'TEST,23479234,"Just Right"" 950g, BO",02/04/2006,,5678,9999,1111,
            'TEST23479234 'Kellogg''s Just Right 950g' 02/04/2006 1234 5678 0000 9999
            'TEST23479234 '' 02/04/2006 1234 5678 0000 9999

            bUseQualifier = strTextQualifier.Length()

            'split data based on options..
            If bUseQualifier Then
                'replace double qualifiers for ease of parsing..
                'strLine = strLine.Replace(New String(strTextQualifier, 2), vbTab)

                'loop and find each field..
                Do Until strLine = Nothing

                    If strLine.Substring(0, 1) = strTextQualifier Then

                        'find closing qualifier
                        lngChrPos = strLine.IndexOf(strTextQualifier, 1)

                        'check for missing double qualifiers, unclosed qualifiers
                        Do Until (strLine.Length() - 1) = lngChrPos OrElse lngChrPos = -1 OrElse _
                          strLine.Substring(lngChrPos + 1, 1) = strDataDelimiter

                            lngChrPos = strLine.IndexOf(strTextQualifier, lngChrPos + 1)
                        Loop

                        'get field from line..
                        If lngChrPos = -1 Then
                            strField = strLine.Substring(1)
                            strLine = vbNullString
                        Else
                            strField = strLine.Substring(1, lngChrPos - 1)
                            If (strLine.Length() - 1) = lngChrPos Then
                                strLine = vbNullString
                            Else
                                strLine = strLine.Substring(lngChrPos + 2)
                                If strLine = "" Then
                                    bEmptyLast = True
                                End If
                            End If

                            'strField = String.Format("{0}{1}{2}", strTextQualifier, strField, strTextQualifier)
                        End If

                    Else
                        'find next delimiter..
                        'lngChrPos = InStr(1, strLine, strDataDelimiter)
                        lngChrPos = strLine.IndexOf(strDataDelimiter)

                        'get field from line..
                        If lngChrPos = -1 Then
                            strField = strLine
                            strLine = vbNullString
                        Else
                            strField = strLine.Substring(0, lngChrPos)
                            strLine = strLine.Substring(lngChrPos + 1)
                            If strLine = "" Then
                                bEmptyLast = True
                            End If
                        End If
                    End If

                    ' Now replace double qualifiers with a single qualifier in the "corrected" string
                    strField = strField.Replace(New String(strTextQualifier, 2), strTextQualifier)

                    'restore double qualifiers..
                    'strField = IIf(strField = vbNullChar, vbNullString, strField)
                    'strField = Replace$(strField, vbTab, strTextQualifier)
                    'strField = IIf(strField = vbTab, vbNullString, strField)
                    'strField = strField.Replace(vbTab, strTextQualifier)

                    'save field to array..
                    strNewLine = String.Format("{0}{1}{2}", strNewLine, strQualifierSplitter, strField)

                Loop

                If bEmptyLast = True Then
                    strNewLine = String.Format("{0}{1}", strNewLine, strQualifierSplitter)
                End If

                'trim off first nullchar..
                strNewLine = strNewLine.Substring(1)

                'split new line..
                strList = strNewLine.Split(strQualifierSplitter)
            Else
                If strLine.Substring(strLine.Length - 1, 1) = strDataDelimiter Then
                    strLine = strLine.Substring(0)
                End If
                'no qualifier.. do a simply split..
                strList = strLine.Split(strDataDelimiter)
            End If

            'return result..
            Return strList

        Catch ex As Exception
            Throw New Exception(String.Format("Error Splitting Special String - {0}", ex.Message.ToString()))
        End Try
    End Function

【讨论】:

  • 无需转换。我在 vb 中需要它来解决这个问题。谢谢!
  • 我对每周超过 400 次数据加载使用相同的逻辑,因此它也已经过测试,如果这是答案,请您投票。
【解决方案4】:

如果您想显示一个下划线来表示“之前的空格,就像您在问题中显示的那样,您可以使用:

string[] splitString = t.Replace(" \"", "_\"").Split('"');

【讨论】:

  • 这只是我们在示例中看到的空格,这不是我们想要的效果。
【解决方案5】:

当您开始添加各种异常时,这类事情的正则表达式会变得复杂快速。

尽管如此,如果更多的是为了兴趣和完整性而不是其他任何事情:

(?<term>[a-zA-Z0-9'.=]+)|("(?<term>[^"]+)")

【讨论】:

  • 是否可以将 RegEx 更改为引号内的转义(双)引号,就像您通常在文本限定的 csv 文件(例如从 Excel 或 Access 导出)中看到的那样?
猜你喜欢
  • 2017-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多