如何将剪贴板中的文本拆分为 DataGridView

How to split text from the Clipboard into a DataGridView

我想将从网站复制的文本拆分到 DataGridView 控件中。 我要复制的文本特别来自 Binance 网站,格式如下:

我的 DataGridView 控件包含 9 列:
DatePairTypeSideAveragePriceExecutedAmountTotal.

正在复制

03-17 10:55:03 DOGE/EUR Limit Buy 0.04816 0.04816 11,740.0 11,740.8 565.39840

我想将它粘贴到我的 DataGridView 中以填充相关的列,但是,当我粘贴它时,只有 Date 列的单元格被填充。有没有办法拆分文本?

编辑:
剪贴板内容的二进制表示:

30 33 2d 31 37 20 32 32 3a 35 37 3a 32 38 0d 0a
44 4f 47 45 2f 45 55 52 0d 0a 4c 69 6d 69 74 0d
0a 53 65 6c 6c 0d 0a 30 2e 30 34 38 37 38 0d 0a
30 2e 30 34 38 37 38 0d 0a 33 30 2c 35 32 36 2e
30 0d 0a 33 30 2c 35 32 36 2e 30 0d 0a 31 2c 34
38 39 2e 30 35 38 32 38 0d 0a 30 33 2d 31 37 20
31 33 3a 31 39 3a 33 39 0d 0a 44 4f 47 45 2f 45
55 52 0d 0a 4c 69 6d 69 74 0d 0a 42 75 79 0d 0a
30 2e 30 34 38 30 30 0d 0a 30 2e 30 34 38 30 30
0d 0a 31 2c 31 30 30 2e 38 0d 0a 31 2c 31 30 30
2e 38 0d 0a 35 32 2e 38 33 38 34 30 0d 0a 30 33
2d 31 37 20 31 30 3a 35 35 3a 30 33 0d 0a 44 4f
47 45 2f 45 55 52 0d 0a 4c 69 6d 69 74 0d 0a 42
75 79 0d 0a 30 2e 30 34 38 31 36 0d 0a 30 2e 30
34 38 31 36 0d 0a 31 31 2c 37 34 30 2e 38 0d 0a
31 31 2c 37 34 30 2e 38 0d 0a 35 36 35 2e 34 33
36 39 33 0d 0a 30 33 2d 31 37 20 31 30 3a 33 31
3a 35 33 0d 0a 44 4f 47 45 2f 45 55 52 0d 0a 4c
69 6d 69 74 0d 0a 42 75 79 0d 0a 30 2e 30 34 38
32 30 0d 0a 30 2e 30 34 38 32 30 0d 0a 31 31 2c
39 37 30 2e 33 0d 0a 31 31 2c 39 37 30 2e 33 0d
0a 35 37 36 2e 39 36 38 34 36

编辑2:
第二个二进制文件

30 33 2d 31 37 20 32 32 3a 35 37 3a 32 38 0d 0a
44 4f 47 45 2f 45 55 52 0d 0a 4c 69 6d 69 74 0d
0a 53 65 6c 6c 0d 0a 30 2e 30 34 38 37 38 0d 0a
30 2e 30 34 38 37 38 0d 0a 33 30 2c 35 32 36 2e
30 0d 0a 33 30 2c 35 32 36 2e 30 0d 0a 31 2c 34
38 39 2e 30 35 38 32 38

尝试这样的事情

Private _yourCopiedRows As String
Private _temporaryArray() As String

_yourCopiedRows = "the value from your clipboard"

_temporaryArray = Split(_yourCopiedRows, " ")

然后将它们一一粘贴到DataGridView的列中

DataGridView.Rows.Add(_temporaryArray(0).ToString, _temporaryArray(1).ToString, etc..)

但我认为最好编写自己的从剪贴板粘贴到 DataGridView 的方法。

Strings.Split Method

在此处发布的示例十六进制数据中,数据源中的所有字段都是从 Web Table 复制的,由 0x0D 0x0A 分隔(\r\n,即 ChrW(13) ChrW(10),即 vbCrLf)。 行也是如此。

要解析此格式,您需要知道有多少个字段组成一行,以确定何时使用回车 Return+换行定义字段或行的边界。
在此处提供的示例中,数据源由 9 个字段组成,因此我保留此引用作为要考虑的格式。
当然,简单的解析器可以适应不同的格式,以备不时之需。

将源数据从 WebBrowser 复制到剪贴板后,我们可以使用 Clipboard.GetText().
以文本形式检索数据 在这里,我从文本的开头和结尾修剪任何 ChrW(13) ChrW(10) ChrW(32),以防在选择 HTML 文本时错误地添加了其中一些。

解析器从文本中检索所有部分并检查生成的字符串数组是否是 9 的倍数。如果不是,则抛出异常(我们无法解析这种格式,假设一个 Row 将包含 9 个字段)。

然后将字符串数组转换为 Object() 数组,其中包含已转换为目标类型的所有值。该数组用作数据新行的来源Table - 附加BindingSource - 用作数据的来源DataGridView.
DataTable 还定义了一个用作自增索引的 Column。


在表单构造函数中,调用 InitializeDataSource()InitializeBinanceUI() 方法初始化数据源和 DataGridView。
这些方法初始化 DataTable 和 DataGridView 列的基本格式,以及用于更改其中一个列的文本颜色的事件处理程序。

注意:这里的DataGridView命名为dgvBinance。在表单设计器中添加一个并重命名为这样。

Imports System.ComponentModel
Imports System.Data
Imports System.Globalization

Private binanceSource As BindingSource = Nothing
Private binanceData As DataTable = Nothing

Public Class SomeForm
    Public Sub New()
        InitializeComponent()
        ' [...]
        InitializeDataSource()
        InitializeBinanceUI()
    End Sub

    Private Sub InitializeDataSource()
        binanceData = New DataTable("BinanceData")
        binanceData.Columns.Add(New DataColumn() With {
            .ColumnName = "Index",
            .AutoIncrement = True,
            .AutoIncrementSeed = 1,
            .AutoIncrementStep = 1
        })

        binanceData.Columns.Add("Date", GetType(Date))
        binanceData.Columns.Add("Pair", GetType(String))
        binanceData.Columns.Add("Type", GetType(String))
        binanceData.Columns.Add("Side", GetType(String))

        binanceData.Columns.Add("Average", GetType(Decimal))
        binanceData.Columns.Add("Price", GetType(Decimal))
        binanceData.Columns.Add("Executed", GetType(Decimal))
        binanceData.Columns.Add("Amount", GetType(Decimal))
        binanceData.Columns.Add("Total", GetType(Decimal))
    End Sub

    Private Sub InitializeBinanceUI()
        AddHandler dgvBinance.CellFormatting, AddressOf dgvBinanceCellFormatting
        binanceSource = New BindingSource(binanceData, "")
        dgvBinance.DataSource = binanceSource
        dgvBinance.Columns("Date").DefaultCellStyle.Format = "MM-dd H:mm:ss"
        dgvBinance.Columns("Average").DefaultCellStyle.Format = "N5"
        dgvBinance.Columns("Price").DefaultCellStyle.Format = "N5"
        dgvBinance.Columns("Executed").DefaultCellStyle.Format = "N1"
        dgvBinance.Columns("Amount").DefaultCellStyle.Format = "N1"
        dgvBinance.Columns("Total").DefaultCellStyle.Format = "N5"
    End Sub

    Private Sub dgvBinanceCellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs)
        If e.Value Is Nothing OrElse dgvBinance.Columns(e.ColumnIndex).Name <> "Side" Then Return
        e.CellStyle.ForeColor = If(e.Value.ToString().Equals("Buy"), Color.Green, Color.Red)
    End Sub
End Sub

当您需要将新行粘贴到控件中时,从剪贴板获取文本并调用解析器,传递从剪贴板获取的文本和用作数据源的数据Table。
使用 DataTable 作为源的 BindingSource 将更新 UI.

Dim sourceData = Clipboard.GetText(TextDataFormat.Text)
Dim rowsAdded = BinanceParseCopyData(sourceData, binanceData)

解析器:

Private Function BinanceParseCopyData(input As String, dataSource As DataTable) As Integer
    Dim culture = CultureInfo.InvariantCulture
    input.Trim({ChrW(13), ChrW(10), ChrW(32)})

    Dim allData = input.Split({vbCrLf}, StringSplitOptions.RemoveEmptyEntries)
    If allData.Length Mod 9 <> 0 Then
        Throw New FormatException($"Unexpected Data Format. A Data Row must be composed of 9 Columns. Found {allData.Length}")
    End If

    Dim rowsCount As Integer = 0
    For pos As Integer = 0 To allData.Length - 1 Step 9
        Dim row As Object() = New Object(9) {}
        Array.Copy(allData, pos, row, 1, 9)
        ' row(0) remains null, since the Column at this index is used by 
        ' the DataTable for the automatic indexer (and expects null as value)
        row(1) = Date.ParseExact(row(1).ToString().Trim(), "MM-dd H:mm:ss", culture)
        row(2) = row(2).ToString().Trim()
        row(3) = row(3).ToString().Trim()
        row(4) = row(4).ToString().Trim()
        row(5) = Decimal.Parse(row(5).ToString().Trim(), NumberStyles.AllowDecimalPoint Or NumberStyles.AllowThousands, culture)
        row(6) = Decimal.Parse(row(6).ToString().Trim(), NumberStyles.AllowDecimalPoint Or NumberStyles.AllowThousands, culture)
        row(7) = Decimal.Parse(row(7).ToString().Trim(), NumberStyles.AllowDecimalPoint Or NumberStyles.AllowThousands, culture)
        row(8) = Decimal.Parse(row(8).ToString().Trim(), NumberStyles.AllowDecimalPoint Or NumberStyles.AllowThousands, culture)
        row(9) = Decimal.Parse(row(9).ToString().Trim(), NumberStyles.AllowDecimalPoint Or NumberStyles.AllowThousands, culture)
        dataSource.Rows.Add(row)
        rowsCount += 1
    Next
    Return rowsCount
End Function

结果的图形示例:


动画中的Form和DataGridView可以在这个PasteBin中找到:
Form class + Designer

ContextMenuStrip 是使用附加到 可替换 颜色定义 class 的自定义 ToolStripProfessionalRenderer which uses a custom ProfessionalColorTable 设计的(可以在 运行 处用另一个颜色定义替换) -时间或设计时间)。
用于自定义的所有对象都张贴在这里: