about charset op

本文介绍了一个用于检测文本是否为合法UTF-8编码的C++函数。该函数通过逐字节检查输入字符串来判断其是否符合UTF-8编码规则,并允许一定程度的错误容忍。

在s60Webkit里看到的,之前项目里也需要这个功能(判断一个文本文件是什么编码),自己找资料写,费时还不一定正确。

/*判断这符串是否合法的utf-8编码*/

bool validateUtf8(const char* chs, int len, int& validMultiByteChars)
{
    // test if this really is utf8
    const char* b = chs;
    const char* e = b+len;
    const char* c = b;
    int seqRem=0;
    bool isUtf8 = true;
    bool wrongUtf8 = false;
    validMultiByteChars = 0;
    while (c<e)
        {
        if( seqRem == 0 ) 
            b = c;
        // test validity of a multibyte sequence
        if (seqRem>0) {
            // a byte in sequence must match 10xxxxxx
            if ((*c & 0xc0) == 0x80)
                seqRem--;
            else {
                //Some times, there is wrong UTF-8 encoding in the characters.
                //For example ( 0xd8 0x73). Then allow atleat one byte wrong encoding.
                //This has been found in the real site. Also, this means here that is a 
                //ASCII character.  ASCII can be handled in the UTF-8 also. 
                wrongUtf8 = true;
            }
            if (seqRem==0)
                validMultiByteChars++;
        }
        // single byte in ascii range 0xxxxxxx
        else if ((*c & 0x80) == 0x00)
            { } // do nothing
        // start of a two byte sequence 110xxxxx 10xxxxxx
        else if ((*c & 0xe0) == 0xc0)
            seqRem=1;
        // start of a three byte sequence 1110xxxx 10xxxxxx 10xxxxxx
        else if ((*c & 0xf0) == 0xe0)
            seqRem=2;
        // start of a four byte sequence 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
        else if ((*c & 0xf8) == 0xf0)
            seqRem=3;
        else if (c-b>3) {
            isUtf8 = false;
            break;
        }
        if ( wrongUtf8 ){
             if( seqRem == 1 ){
                 seqRem--; 
                 wrongUtf8 = false;
             }
             else {
                 isUtf8 = false;
                 break; 
             }
         } //end if ( wrongUtf8 )
        c++;
    } //end while
    return isUtf8;
}


 

 

 

aaaaaaaaaaa

 

 

 

bbbbbbbbbbb

 

 

 

ccccccccccccccc

<!-- 权限管理 --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" href="../../layui/css/layui.css"> <link rel="stylesheet" href="../../css/diy.css"> <style> .layui-body { overflow-x: scroll; } </style> </head> <body> <div class="section1"> <!-- 内容主体区域 --> <div class="manu auth" style="padding: 15px;"> <form class="layui-form" action=""> <div class="form-input-box-t layui-form-item"> <div class="input-box"> <label class="layui-form-label">权限名</label> <div class="layui-input-block input-i block"> <input type="text" name="mod_name" required lay-verify="required" autocomplete="off" class="layui-input"> <!--通过lay-verify="required"实现输入验证,确保必填字段非空--> </div> </div> <div class="input-box"> <!--查询部分--> <label class="layui-form-label">用户组</label> <div class="layui-input-block select block"> <select name="user_group" lay-filter="required" id="user_group"> <option value=""></option> </select> </div> </div> <div class="input-box"> <label class="layui-form-label">添加权限</label> <div class="layui-input-block select block"> <select name="add" lay-filter="required"> <option value=""></option> <option value="0">无</option> <option value="1">有</option> </select> </div> </div> <div class="input-box"> <label class="layui-form-label">修改权限</label> <div class="layui-input-block select block"> <select name="set" lay-filter="required"> <option value=""></option> <option value="0">无</option> <option value="1">有</option> </select> </div> </div> <div class="input-box"> <label class="layui-form-label">删除权限</label> <div class="layui-input-block select block"> <select name="del" lay-filter="required"> <option value=""></option> <option value="0">无</option> <option value="1">有</option> </select> </div> </div> <div class="input-box"> <label class="layui-form-label">查询权限</label> <div class="layui-input-block select block"> <select name="get" lay-filter="required"> <option value=""></option> <option value="0">无</option> <option value="1">有</option> </select> </div> </div> </div> </form> <div class="buts"> <button type="button" class="layui-btn layui-btn-normal" id="inquire"><span>查询</span></button> <button type="button" class="layui-btn layui-btn-normal" id="reset"><span>重置</span></button> </div> <div class="Customize-the-box"> <div class="circle"></div> <div class="circle"></div> <div class="card-inner"></div> </div> </div> <h1>数据列表</h1> <div class="table"> <table class="layui-hide" id="newsClassification" lay-filter="newsClassification"></table> <script type="text/html" id="toolbarDemo"> <div class="layui-btn-container"> <button class="layui-btn layui-btn-sm" lay-event="add">修改</button> </div> </script> </div> </div> <script src="../../layui/layui.js"></script> <script src="../../js/axios.min.js"></script> <script src="../../js/index.js"></script> <script src="../../js/base.js" charset="utf-8"></script> <script> var BaseUrl = baseUrl() layui.use(['element', 'layer', 'util'], function () { var element = layui.element , table = layui.table , layer = layui.layer , util = layui.util , $ = layui.$; let personInfo = JSON.parse(sessionStorage.personInfo) let user_group = personInfo.user_group let token = sessionStorage.token || null //头部事件 util.event('lay-header-event', { //左侧菜单事件 menuLeft: function (othis) { layer.msg('展开左侧菜单的操作', {icon: 0}); } , menuRight: function () { layer.open({ type: 1 , content: '<div style="padding: 15px;">处理右侧面板的操作</div>' , area: ['260px', '100%'] , offset: 'rt' //右上角 , anim: 5 , shadeClose: true }); } }); // table 事件 table.render({ elem: '#newsClassification' , toolbar: true , url: BaseUrl + '/api/auth/get_list' , headers: { 'x-auth-token': token, 'Content-Type': 'application/json' } ,limits: [10] , page: { //支持传入 laypage 组件的所有参数(某些参数除外,如:jump/elem) - 详见文档 layout: ['limit', 'count', 'prev', 'page', 'next', 'skip'] //自定义分页布局 //,curr: 5 //设定初始在第 5 页 , groups: 1 //只显示 1 个连续页码 , first: false //不显示首页 , last: false //不显示尾页 } , cols: [[ {type: 'checkbox'} , {field: 'user_group', width: '10%', title: '用户组'} , {field: 'mod_name', width: '10%', title: '权限名称', templet: function (d) { if (d.path.replace('/'+d.table_name+'/','')=='table') { return "<div>"+d.mod_name+"后台列表</div>" } if (d.path.replace('/'+d.table_name+'/','')=='view') { return "<div>"+d.mod_name+"后台详情</div>" } if (d.path.replace('/'+d.table_name+'/','')=='list') { return "<div>"+d.mod_name+"前台列表</div>" } if (d.path.replace('/'+d.table_name+'/','')=='details') { return "<div>"+d.mod_name+"前台详情</div>" } if (d.path.replace('/'+d.table_name+'/','')=='edit') { return "<div>"+d.mod_name+"前台编辑</div>" } } } , { field: 'add', width: '10%', title: '<span>添加</span>权限', templet: function (d) { if (d.add == '0') { return "<div>无</div>" } else { return "<div>有</div>" } } } , { field: 'del', width: '10%', title: '<span>删除</span>权限', templet: function (d) { if (d.del == '0') { return "<div>无</div>" } else { return "<div>有</div>" } } } , { field: 'set', width: '10%', title: '修改权限', templet: function (d) { if (d.set == '0') { return "<div>无</div>" } else { return "<div>有</div>" } } } , { field: 'get', width: '10%', title: '<span>查询</span>权限', templet: function (d) { if (d.get == '0') { return "<div>无</div>" } else { return "<div>有</div>" } } } , { field: 'create_time', width: '15%', title: '新增时间', sort: true, templet: "<div>{{layui.util.toDateString(d.create_time, 'yyyy-MM-dd HH:mm:ss')}}</div>" } , { field: 'update_time', width: '15%', title: '更新时间', sort: true, templet: "<div>{{layui.util.toDateString(d.update_time, 'yyyy-MM-dd HH:mm:ss')}}</div>" } , {field: 'operate', title: '操作', toolbar: "#toolbarDemo"} ]] , page: true, request: { limitName: 'size' }, response: { statusName: 'code', //规定返回/Back的状态码字段为code statusCode: 200 //规定成功的状态码味200 }, parseData: function (res) { return { "code": 200, "msg": "", "count": res.result.count, "data": res.result.list } }, where: {like: 0, size: 10} }); layui.table.on('tool(newsClassification)', function (obj) { //注:tool是工具条事件名,test是table原始容器的属性 lay-filter="对应的值" var data = obj.data; //获得当前行数据 var layEvent = obj.event; //获得 lay-event 对应的值(也可以是表头的 event 参数对应的值) var tr = obj.tr; //获得当前行 tr 的DOM对象 if (layEvent == "add") { let auth_id = data.auth_id // window.location = ('./view.html?' + auth_id) layopen_dateil('./view.html?' + auth_id) } }); // 请求参数: let request = {like: 0, size: 10, page: 1, mod_name: '', user_group: '',add:'',set:'',del:'',get:'',orderby: 'create_time desc'} // <span>重置</span>/Reset参数 let resetName = {like: 0, size: 10, page: 1, orderby: 'create_time desc'} fun('newsClassification', BaseUrl + '/api/auth/del', 'auth_id', request, resetName) async function get_list_user_group() { $.ajax({ url: BaseUrl + "/api/user_group/get_list", type: "get", async: false, success: function (data) { if (data && typeof data === 'string'){ data = JSON.parse(data); } if (data.result) { // 拿到单选框的父级节点 let select = document.querySelector("#user_group") let op1 = document.createElement('option') select.appendChild(op1) // 收集数据 长度 let count // 收集数据 数组 let arr = [] count = data.result.count arr = data.result.list for (let i = 0; i < arr.length; i++) { // 创建节点 let op = document.createElement('option') // 给节点赋值 op.innerHTML = arr[i].name op.value = arr[i].name // 新增/Add节点 select.appendChild(op) layui.form.render('select') } } } }); } get_list_user_group(); }); </script> </body> </html> 逐个分析代码功能,不要自己填写内容
05-28
Option Explicit Private currentPairIndex As Long Private currentRow As Long Private currentColumn As Long Private currentOperation As String Private targetPath As String Private sourceFilePath As String Private dataPoints As Long Private maxRow As Long Sub ConvertColumnPairsToCSV() On Error GoTo ErrorHandler ' Initialize variables Dim sourceFile As Variant Dim wbSource As Workbook Dim wsSource As Worksheet Dim fileName As String Dim startTime As Double Dim processedCells As Long Dim i As Long, pairIndex As Long, rowIndex As Long ' Reset tracking variables ResetTrackingVariables ' Start timer startTime = Timer processedCells = 0 dataPoints = 0 ' Define column pairs Dim colPairs() As Variant colPairs = Array( _ Array(Array(4, 5), "D:E"), _ Array(Array(9, 10), "I:J"), _ Array(Array(11, 12), "K:L"), _ Array(Array(13, 14), "M:N"), _ Array(Array(15, 16), "O:P"), _ Array(Array(17, 18), "Q:R"), _ Array(Array(19, 20), "S:T"), _ Array(Array(21, 22), "U:V"), _ Array(Array(23, 24), "W:X"), _ Array(Array(25, 26), "Y:Z"), _ Array(Array(27, 28), "AA:AB") _ ) ' Step 1: Select source file currentOperation = "Selecting source file" sourceFile = Application.GetOpenFilename( _ FileFilter:="Excel Files (*.xlsx; *.xls; *.xlsm), *.xlsx; *.xls; *.xlsm", _ Title:="Select Source Excel File") If VarType(sourceFile) = vbBoolean And sourceFile = False Then Exit Sub sourceFilePath = CStr(sourceFile) ' Step 2: Open workbook currentOperation = "Opening workbook" Application.ScreenUpdating = False Application.StatusBar = "Opening source file..." Set wbSource = Workbooks.Open(sourceFile, ReadOnly:=True, IgnoreReadOnlyRecommended:=True) ' Step 3: Get worksheet Set wsSource = SelectWorksheet(wbSource) If wsSource Is Nothing Then wbSource.Close False Exit Sub End If ' Step 4: Detect data in columns currentOperation = "Detecting data in columns" Application.StatusBar = "Scanning worksheet for data..." ' Enhanced data detection with detailed diagnostics Dim hasData As Boolean hasData = DetectDataInColumns(wsSource, colPairs) ' If no data found, show detailed diagnostics If Not hasData Then wbSource.Close False ShowNoDataDiagnostics wsSource, colPairs, sourceFilePath Exit Sub End If ' Step 5: Get output file details currentOperation = "Getting output file details" fileName = CStr(Application.InputBox("Enter output file name (without extension):", "File Name", "OP_Report", Type:=2)) If fileName = "" Or fileName = "False" Then wbSource.Close False Exit Sub End If ' Get save path Dim saveDialogResult As Variant saveDialogResult = GetSavePath(fileName) If VarType(saveDialogResult) = vbBoolean And saveDialogResult = False Then wbSource.Close False Application.StatusBar = False Exit Sub End If targetPath = CStr(saveDialogResult) ' Step 6: Process and save data currentOperation = "Processing and saving data" If ProcessAndSaveData(wsSource, colPairs, targetPath, processedCells) Then ' Completion message MsgBox "CSV file generated successfully!" & vbCrLf & _ "Saved to: " & targetPath & vbCrLf & _ "Data points found: " & Format(dataPoints, "#,##0") & vbCrLf & _ "Cells processed: " & Format(processedCells, "#,##0") & vbCrLf & _ "Time taken: " & Format(Timer - startTime, "0.00") & " seconds", _ vbInformation, "Process Complete" End If ' Cleanup Cleanup wbSource ExitSub: Application.StatusBar = False Application.ScreenUpdating = True Exit Sub ErrorHandler: HandleError GoTo ExitSub End Sub ' ========================================================= ' Core Functions ' ========================================================= Private Sub ResetTrackingVariables() currentPairIndex = -1 currentRow = -1 currentColumn = -1 currentOperation = "Initialization" targetPath = "" sourceFilePath = "" dataPoints = 0 maxRow = 0 End Sub Private Function SelectWorksheet(wb As Workbook) As Worksheet On Error Resume Next currentOperation = "Selecting worksheet" Dim wsName As String wsName = CStr(Application.InputBox("Enter the worksheet name to process:", "Worksheet Selection", Type:=2)) If wsName = "" Or wsName = "False" Then Set SelectWorksheet = Nothing Exit Function End If Set SelectWorksheet = wb.Sheets(wsName) If SelectWorksheet Is Nothing Then MsgBox "Worksheet '" & wsName & "' not found!", vbExclamation End If End Function Private Function DetectDataInColumns(ws As Worksheet, colPairs As Variant) As Boolean ' Check source columns B and C Dim col As Long Dim cellValue As String ' Check column B For col = 2 To 3 currentColumn = col Dim lastRow As Long lastRow = ws.Cells(ws.Rows.Count, col).End(xlUp).row For currentRow = 1 To lastRow cellValue = GetCellValue(ws, currentRow, col) If Len(Trim(cellValue)) > 0 Then dataPoints = dataPoints + 1 DetectDataInColumns = True End If Next currentRow Next col ' Check column pairs Dim i As Long, j As Long For i = LBound(colPairs) To UBound(colPairs) Dim pair As Variant pair = colPairs(i) Dim columns As Variant columns = pair(0) For j = LBound(columns) To UBound(columns) col = SafeConvertToLong(columns(j)) currentColumn = col lastRow = ws.Cells(ws.Rows.Count, col).End(xlUp).row For currentRow = 1 To lastRow cellValue = GetCellValue(ws, currentRow, col) If Len(Trim(cellValue)) > 0 Then dataPoints = dataPoints + 1 DetectDataInColumns = True ' Update maxRow for later processing If currentRow > maxRow Then maxRow = currentRow End If Next currentRow Next j Next i ' If no data found, scan entire worksheet If Not DetectDataInColumns Then DetectDataInColumns = ScanEntireWorksheet(ws) End If End Function Private Function ScanEntireWorksheet(ws As Worksheet) As Boolean ' Last resort: scan entire worksheet for any data On Error Resume Next Dim usedRange As Range Set usedRange = ws.usedRange If usedRange Is Nothing Then ScanEntireWorksheet = False Exit Function End If Dim cell As Range For Each cell In usedRange If Len(Trim(cell.value)) > 0 Then dataPoints = dataPoints + 1 ScanEntireWorksheet = True End If Next cell End Function Private Function GetSavePath(fileName As String) As Variant currentOperation = "Getting save path" GetSavePath = Application.GetSaveAsFilename( _ InitialFileName:=fileName & ".csv", _ FileFilter:="CSV Files (*.csv), *.csv", _ Title:="Save CSV File") End Function Private Function ProcessAndSaveData( _ ws As Worksheet, _ colPairs As Variant, _ savePath As String, _ ByRef processedCells As Long) As Boolean On Error GoTo ErrorHandler ' Create UTF-8 encoded CSV currentOperation = "Creating CSV file" Application.StatusBar = "Creating CSV file..." Dim stream As Object Set stream = CreateObject("ADODB.Stream") stream.Charset = "UTF-8" stream.Open stream.WriteText ChrW(&HFEFF) ' UTF-8 BOM ' Create header Dim headerLine As String headerLine = "Source B,Source C" Dim i As Long For i = 0 To UBound(colPairs) headerLine = headerLine & ",Column Pair " & (i + 1) & " (" & colPairs(i)(1) & ")" Next i stream.WriteText headerLine & vbCrLf ' Process data row by row Dim columns As Variant Dim col1 As Long, col2 As Long Dim sourceBValue As String, sourceCValue As String Dim outputLine1 As String, outputLine2 As String Dim formattedValue As String Dim dataFound As Boolean dataFound = False ' Use maxRow from detection or calculate if needed If maxRow = 0 Then On Error Resume Next maxRow = ws.usedRange.Rows.Count If Err.Number <> 0 Then maxRow = 1000 ' Default max On Error GoTo ErrorHandler End If For currentRow = 1 To maxRow ' Get values from columns B and C sourceBValue = GetFormattedCellValue(ws, currentRow, 2) sourceCValue = GetFormattedCellValue(ws, currentRow, 3) outputLine1 = sourceBValue & "," & sourceCValue outputLine2 = sourceBValue & "," & sourceCValue Dim hasDataInRow As Boolean hasDataInRow = (Len(Trim(sourceBValue)) > 0) Or (Len(Trim(sourceCValue)) > 0) ' Process each column pair For currentPairIndex = 0 To UBound(colPairs) columns = colPairs(currentPairIndex)(0) col1 = SafeConvertToLong(columns(0)) col2 = SafeConvertToLong(columns(1)) ' Process first column currentColumn = col1 formattedValue = GetFormattedCellValue(ws, currentRow, col1) outputLine1 = outputLine1 & "," & formattedValue ' Process second column currentColumn = col2 formattedValue = GetFormattedCellValue(ws, currentRow, col2) outputLine2 = outputLine2 & "," & formattedValue If Not hasDataInRow Then hasDataInRow = (Len(Trim(formattedValue)) > 0) End If processedCells = processedCells + 2 Next currentPairIndex If hasDataInRow Then stream.WriteText outputLine1 & vbCrLf stream.WriteText outputLine2 & vbCrLf dataFound = True End If Next currentRow ' Final check for data If Not dataFound Then stream.Close Set stream = Nothing ShowNoDataDiagnostics ws, colPairs, sourceFilePath ProcessAndSaveData = False Exit Function End If ' Save file currentOperation = "Saving CSV file" Application.StatusBar = "Saving CSV file..." SaveStreamToFile stream, savePath stream.Close Set stream = Nothing ProcessAndSaveData = True Exit Function ErrorHandler: HandleError On Error Resume Next If Not stream Is Nothing Then If stream.State = 1 Then stream.Close Set stream = Nothing End If ProcessAndSaveData = False End Function Private Sub SaveStreamToFile(stream As Object, savePath As String) Dim saveAttempt As Integer Dim saveSuccessful As Boolean saveSuccessful = False For saveAttempt = 1 To 3 On Error Resume Next stream.SaveToFile savePath, 2 If Err.Number = 0 Then saveSuccessful = True Exit For Else Application.Wait Now + TimeValue("00:00:00.5") Err.Clear End If Next saveAttempt On Error GoTo 0 If Not saveSuccessful Then Err.Raise 3004, "SaveToFile", "Failed to save file after 3 attempts. Please check file permissions or if file is open." End If End Sub ' ========================================================= ' Diagnostic Functions ' ========================================================= Private Sub ShowNoDataDiagnostics(ws As Worksheet, colPairs As Variant, filePath As String) Dim msg As String msg = "No data found in any of the specified columns." & vbCrLf & vbCrLf msg = msg & "Detailed Diagnostics:" & vbCrLf msg = msg & "--------------------------------------------------" & vbCrLf msg = msg & "File Path: " & filePath & vbCrLf msg = msg & "Worksheet: " & ws.Name & vbCrLf & vbCrLf ' Worksheet metrics On Error Resume Next msg = msg & "Worksheet Metrics:" & vbCrLf msg = msg & "- Total Rows: " & Format(ws.usedRange.Rows.Count, "#,##0") & vbCrLf msg = msg & "- Total Columns: " & Format(ws.usedRange.columns.Count, "#,##0") & vbCrLf msg = msg & "- Total Cells: " & Format(ws.usedRange.Cells.Count, "#,##0") & vbCrLf msg = msg & "- Data Points Found: " & Format(dataPoints, "#,##0") & vbCrLf & vbCrLf ' Column analysis msg = msg & "Column Analysis:" & vbCrLf msg = msg & "Columns Checked:" & vbCrLf msg = msg & "- B (Source)" & vbCrLf msg = msg & "- C (Source)" & vbCrLf Dim i As Long, j As Long For i = 0 To UBound(colPairs) Dim cols As Variant cols = colPairs(i)(0) Dim desc As String desc = colPairs(i)(1) msg = msg & "- " & desc & " (Pair " & (i + 1) & ")" & vbCrLf Next i ' Data presence in columns msg = msg & vbCrLf & "Data Presence in Key Columns:" & vbCrLf msg = msg & CheckColumnForData(ws, "B (Source)", 2) msg = msg & CheckColumnForData(ws, "C (Source)", 3) For i = 0 To UBound(colPairs) Dim pair As Variant pair = colPairs(i) Dim pairCols As Variant pairCols = pair(0) Dim pairDesc As String pairDesc = pair(1) For j = LBound(pairCols) To UBound(pairCols) msg = msg & CheckColumnForData(ws, pairDesc & " - Col " & pairCols(j), pairCols(j)) Next j Next i ' Suggested solutions msg = msg & vbCrLf & "Possible Solutions:" & vbCrLf msg = msg & "1. Verify the correct worksheet is selected" & vbCrLf msg = msg & "2. Check if data is in different columns than specified" & vbCrLf msg = msg & "3. Ensure data isn't hidden by filters or grouping" & vbCrLf msg = msg & "4. Confirm the file contains actual data (not just formulas)" & vbCrLf msg = msg & "5. Try selecting a different file or worksheet" & vbCrLf msg = msg & "6. Check for leading/trailing spaces with TRIM()" & vbCrLf ' Display detailed message CreateDiagnosticForm msg End Sub Private Function CheckColumnForData(ws As Worksheet, colDesc As String, colNum As Long) As String On Error Resume Next Dim result As String result = colDesc & ": " Dim lastRow As Long lastRow = ws.Cells(ws.Rows.Count, colNum).End(xlUp).row If lastRow = 1 And IsEmpty(ws.Cells(1, colNum)) Then result = result & "NO DATA" & vbCrLf Else Dim dataCount As Long dataCount = 0 Dim i As Long For i = 1 To lastRow If Not IsEmpty(ws.Cells(i, colNum)) Then dataCount = dataCount + 1 End If Next i If dataCount > 0 Then result = result & Format(dataCount, "#,##0") & " data points" & vbCrLf Else result = result & "NO DATA (cells appear empty)" & vbCrLf End If End If CheckColumnForData = result End Function 修正错误, 函数没定义
最新发布
12-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值