当前位置: 首页 > news >正文

PDF发票解析并将信息回填到前端(1)后端解析PDF

文章目录

  • 参考文章
    • 技术栈
    • 需求
    • 解析发票类型
  • 1. 最终项目结构
    • 1.1 说明
  • 2. 相关代码
    • 2.1 导入相应的maven依赖
    • 2.2 实体类
    • 2.3 工具类
    • 2.4 三层架构
      • controller
      • service
      • mapper

参考文章

参考文章

技术栈

SpringBoot+Vue

需求

本文主要是实现提取发票中的部分内容,并实现自动回填到页面中对应位置。

解析发票类型

在这里插入图片描述

1. 最终项目结构

新建一个Springboot项目

在这里插入图片描述

1.1 说明

  1. 实体 entity 包下
    • 主要有两个实体,分别是发票实体NewInvoice,和发票备注实体Note
  2. 工具 utils 包下
    • PDF类用于解析PDF文件
    • InvoiceRegexEnum 类是发票信息的正则表达式枚举类,提取发票信息所用到的正则表达式都在这个枚举类中

2. 相关代码

2.1 导入相应的maven依赖

<!--        添加依赖开始位置--><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.21</version></dependency><dependency><groupId>org.apache.pdfbox</groupId><artifactId>fontbox</artifactId><version>2.0.21</version></dependency><dependency><groupId>org.apache.pdfbox</groupId><artifactId>jempbox</artifactId><version>1.8.13</version></dependency><dependency><groupId>org.apache.pdfbox</groupId><artifactId>xmpbox</artifactId><version>2.0.0</version></dependency><dependency><groupId>org.apache.pdfbox</groupId><artifactId>preflight</artifactId><version>2.0.0</version></dependency><dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox-tools</artifactId><version>2.0.0</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.0.0</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.0.0</version></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.1.0</version></dependency><dependency><groupId>com.google.zxing</groupId><artifactId>javase</artifactId><version>3.1.0</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.11.0</version></dependency><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId></dependency><!--        添加依赖结束位置-->

2.2 实体类

电子发票实体类NewInvoice

package com.example.pdf.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.math.BigDecimal;/*** 电子发票实体类*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class NewInvoice {
//    private String  fileAbsolutePath;   // 文件绝对路径private String number;  // 发票号码private String date;    // 开票日期
//    private String sellerName;  // 销售方名称private BigDecimal amount;  // 合计金额private BigDecimal taxAmount;   // 合计税额private BigDecimal totalAmount; // 价税合计金额private Note Detail;    //  发票备注信息private String note;    //  备注}

备注实体类Note

package com.example.pdf.entity;import lombok.Data;/*** 发票备注信息*/
@Data
public class Note {private String buyer; // 购方private String buyerAccount; // 购方银行账号private String seller; // 销方private String sellerAccount; // 销方银行账号private String payee; // 收款人private String checker; // 复核人
//    @Override
//    public String toString() {
//        return  "购方开户银行:" + buyer + ";    "+
//                "银行账号:" + buyerAccount + ";" +"\n"+
//                "销方开户银行:" + seller + ";    "+
//                "银行账号:" + sellerAccount +";" +"\n\n"+
//                " 收款人:" + payee + ";" +"    "+
//                " 复核人:" + checker +";";
//    }
}

2.3 工具类

正则表达式枚举类

package com.example.pdf.utils;/*** 正则表达式枚举类*/
public enum InvoiceRegexEnum {/*** 机器编码、发票代码、发票号码、开票日期和校验码的提取正则*/REGULAR_A("机器编号:(?<machineNumber>\\d{12})|发票代码:(?<code>\\d{12})|发票号码:(?<number>\\d{8})|:(?<date>\\d{4}年\\d{2}月\\d{2}日)|校验码:(?<checksum>\\d{20}|\\S{4,})"),/*** 新版发票的机器编码、发票代码、发票号码、开票日期和校验码的提取正则*/REGULAR_A_NEW("发票号码:(?<number>\\d{20})|:(?<date>\\d{4}年\\d{2}月\\d{2}日)|(售名称|销名称):(?<name>\\S*)"),/*** 发票号码备用提取正则*/REGULAR_A_1("(国制|制普通发票)(?<number>\\d{8})"),/*** 发票号码跨行提取正则*/REGULAR_A_1R("发票号码:(?<number>\\d{7})[\\s\\S]*?(\\d+)"),/*** 开票日期备用提取正则*/REGULAR_A_2("开票日期:(?<date>\\d{4}\\d{2}月\\d{2}日)"),/*** 发票代码备用提取正则*/REGULAR_A_3("发票代码(?<code>\\d{12})"),/*** 发票代码跨行提取正则*/REGULAR_A_3R("发票代码:(?<code>\\d{10})[\\s\\S]*?(\\d+)"),/*** 金额、税额提取正则,匹配形如 "合计¥?金额¥?税额" 的文本*/REGULAR_B("合计¥?(?<amount>[^ \\f\\n\\r\\t\\v*]*)(?:¥?(?<taxAmount>\\S*)|\\*+)\\s"),/*** 金额提取正则,用于匹配结果有误的修正*/REGULAR_BR("合计¥(?<amount>\\d+\\.\\d+)"),/*** 金额、税额备用提取正则*/REGULAR_B_1("合\\u0020*计\\u0020*¥?(?<amount>[^ ]*)\\u0020+¥?(?:(?<taxAmount>\\S*)|\\*+)\\s"),/*** 价税合计提取正则,匹配“价税合计(大写)XXX(小写)¥YYY”格式的文本*/REGULAR_C("价税合计\\u0028大写\\u0029(?<amountString>\\S*)\\u0028小写\\u0029¥?(?<amount>\\S*)\\s"),/*** 收款人、复核、开票人、销售方提取正则,匹配格式为“收款人:xxx复核:xxx开票人:xxx销售方”的字符串*/REGULAR_D("收款人:(?<payee>\\S*)复核:(?<reviewer>\\S*)开票人:(?<drawer>\\S*)销售方"),/*** 发票类型提取正则,匹配"xxx通发票"格式的发票类型*/REGULAR_E("(?<p>\\S*)通发票"),/*** 发票类型提取正则,匹配"xxx用发票"格式的发票类型*/REGULAR_E_1("(?<p>\\S*)用发票"),/*** 发票类型提取 - 辅助正则*/REGULAR_E_AUX("(?:国|统|一|发|票|监|制)"),/*** 购买方信息提取正则*/REGULAR_F("名称:(?<name>\\S*)|纳税人识别号:(?<code>\\S*)|地址、电话:(?<address>\\S*)|开户行及账号:(?<account>\\S*)|电子支付标识:(?<account2>\\S*)"),/*** 针对深圳发票的销售方名称提取正则*/REGULAR_FR("名称:(?<name>\\S*)"),/*** 处理除了金额和税额之外的其他文本元素正则*/REGULAR_G("^(-?\\d+)(\\.\\d+)?$"),/*** 备注信息提取正则*/REGULAR_A_NOTE_BUYER("购方开户银行:(?<buyer>[^;]+);"),REGULAR_A_NOTE_BUYERACCOUNT("银行账号:(?<buyerAccount>\\d+)(?=[,;])"),REGULAR_A_NOTE_SELLER("销方开户银行:(?<seller>.*?)(?=[,;]|\\Z)"),REGULAR_A_NOTE_SELLERACCOUNT("银行账号:(?<sellerAccount>\\d+)(?=[,;]|\\Z)"),REGULAR_A_NOTE_PAYEE("收款人:(?<payee>.*?)(?=[,;]|\\Z)"),REGULAR_A_NOTE_CHECKER("复核人:(?<checker>.*?)(?=[,;]|\\Z)"),/*** 检查当前详细项字符串是否符合特定条件正则*/REGULAR_H("\\S+\\d*(%|免税|不征税|出口零税率|普通零税率)\\S*"),REGULAR_H_1("^ *\\d*(%|免税|不征税|出口零税率|普通零税率)\\S*"),REGULAR_H_2("\\S+\\d+%[\\-\\d]+\\S*"),REGULAR_H_3("^ *\\d*(%|免税|不征税|出口零税率|普通零税率)\\S*");private final String regex;InvoiceRegexEnum(String regex) {this.regex = regex;}public String getRegex() {return regex;}
}

解析PDF工具类

package com.example.pdf.utils;import com.example.pdf.entity.NewInvoice;
import com.example.pdf.entity.Note;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;import static com.example.pdf.utils.InvoiceRegexEnum.*;@Slf4j
public class PDF {private static final String PDF_EXTENSION = ".pdf";/*** 调用该方法将前端接受到的文件暂存** @param file*/public static NewInvoice parsePdfFile(MultipartFile file) {NewInvoice newInvoice = new NewInvoice();try {// 创建一个临时文件Path tempFile = Files.createTempFile("tempPrefix", ".pdf");File tempFilePath = tempFile.toFile();// 将MultipartFile的内容写入到临时文件try (FileOutputStream fos = new FileOutputStream(tempFilePath)) {fos.write(file.getBytes());}// 现在你可以使用临时文件的路径来调用你的解析方法newInvoice = extractInvoiceInformation(tempFilePath.getAbsolutePath());// 删除临时文件,或者在某些情况下保留它tempFilePath.delete();} catch (IOException e) {// 处理异常e.printStackTrace();}// 返回值return newInvoice;}/*** 提取发票信息*//*** 提取发票信息** @param filePath 发票地址* @return*/public static NewInvoice extractInvoiceInformation(String filePath) {// 指定要处理的文件夹路径NewInvoice newInvoice1 = newPdfProcessInvoicesInFile(filePath);String note = "";if (newInvoice1.getDetail().getBuyer() != null) {note = "购方开户银行:" + newInvoice1.getDetail().getBuyer() + ";    ";} else {note = "";}if (newInvoice1.getDetail().getBuyerAccount() != null) {note = note + "银行账号:" + newInvoice1.getDetail().getBuyerAccount() + ";    ";} else {note = note + "";}if (newInvoice1.getDetail().getSeller() != null) {note = note + "销方开户银行:" + newInvoice1.getDetail().getSeller() + ";    ";} else {note = note + "";}if (newInvoice1.getDetail().getSellerAccount() != null) {note = note + "银行账号:" + newInvoice1.getDetail().getSellerAccount() + ";    ";} else {note = note + "";}if (newInvoice1.getDetail().getPayee() != null) {note = note + " 收款人:" + newInvoice1.getDetail().getPayee() + ";" + "    ";} else {note = note + "";}if (newInvoice1.getDetail().getChecker() != null) {note = note + " 复核人:" + newInvoice1.getDetail().getChecker() + ";";} else {note = note + "";}newInvoice1.setNote(note);return newInvoice1;}/*** 处理指定的PDF发票文件** @param filePath 文件路径* @return 包含提取信息的 NewInvoice 列表*/public static NewInvoice newPdfProcessInvoicesInFile(String filePath) {File file = new File(filePath);NewInvoice returnResult = new NewInvoice();if (isPdfFile(file)) {NewInvoice result = extractInvoice(file.getAbsolutePath()); // 提取文件内容if (result != null) {returnResult = createProcessedInvoice(result);// 创建一个新的发票对象} else {handleExtractionError(file);}}return returnResult;}/*** 创建一个处理后的 NewInvoice 对象** @param result 原始的 NewInvoice 对象* @return 处理后的 NewInvoice 对象*/private static NewInvoice createProcessedInvoice(NewInvoice result) {NewInvoice returnResult = new NewInvoice();returnResult.setNumber(result.getNumber());returnResult.setDate(result.getDate());returnResult.setTotalAmount(result.getTotalAmount());returnResult.setAmount(result.getAmount());returnResult.setTaxAmount(result.getTaxAmount());returnResult.setDetail(result.getDetail());return returnResult;}/*** 处理提取失败的情况,输出错误信息** @param file 提取失败的文件*/private static void handleExtractionError(File file) {log.warn("文件: {}\t提取失败~~~\n", file.getName());}/*** 检查文件是否为PDF文件** @param file 要检查的文件* @return 如果是PDF文件,返回 true,否则返回 false*/private static boolean isPdfFile(File file) {return file.isFile() && file.getName().toLowerCase().endsWith(PDF_EXTENSION);}/*** 从本地文件或URL中提取发票信息。** @param filePath 本地文件路径或发票的URL。* @return 包含提取信息的 NewInvoice 对象。*/private static NewInvoice extractInvoice(String filePath) {File sourceFile = new File(filePath);if (!sourceFile.exists()) {log.error("指定的源文件不存在");}NewInvoice result = null;try {// 调用函数解析PDF ,返回 发票对象【基本信息】result = extract(sourceFile);} catch (Exception e) {e.printStackTrace();result = new NewInvoice();}return result;}/*** 解析PDF 文件,返回发票对象** @param file PDF文件* @return* @throws IOException*/public static NewInvoice extract(File file) throws IOException {NewInvoice invoice = new NewInvoice();  // 新建发票对象// 接收一个表示 PDF 文件路径的字符串作为参数,并返回一个 PDDocument 对象。// 这个对象代表了整个PDF 文档,可以通过这个对象来访问文档的各个部分PDDocument doc = PDDocument.load(file);// 从 PDDocument 对象 doc 中获取第一页,并将这个页面对象赋值给PDPage类型的变量// PDPage 对象代表了文档中的一个页面PDPage firstPage = doc.getPage(0);// 获取页面裁剪框宽度,并将宽度四舍五入为整数// 【页面裁剪宽度定义了页面上用于显示内容的区域】int pageWidth = Math.round(firstPage.getCropBox().getWidth());// PDFTextStripper 用于从PDF文档中提取文本的工具PDFTextStripper textStripper = new PDFTextStripper(); // 创建一个实例textStripper.setSortByPosition(true); // 提取文本时按照物理位置进行排序// 提取整个文档的所有文本内容,并将这些文本内容作为一个长字符串返回String fullText = textStripper.getText(doc);// 页面翻转? 不重要if (firstPage.getRotation() != 0) {pageWidth = Math.round(firstPage.getCropBox().getHeight());}// 处理文本中可能有错误的符号String allText = replace(fullText).replaceAll("(", "(").replaceAll(")", ")").replaceAll("¥", "¥");// 提取 新版发票的机器编码、发票代码、发票号码、开票日期和检验码{Pattern pattern = Pattern.compile(REGULAR_A_NEW.getRegex()); // 新版发票的机器编码、发票代码、发票号码、开票日期和检验码的提取正则Pattern patternNumber = Pattern.compile(REGULAR_A_1.getRegex());// 发票号码备用提取正则Pattern patternDate = Pattern.compile(REGULAR_A_2.getRegex()); // 开票日期备用提取正则// matcer 类对于输入字符串进行解释和匹配操作,这些操作是基于某个Pattern对象定义的规则(正则表达式)进行的。// 检查allText 字符串中是否匹配pattern中定义的正则表达式的文本Matcher matcher = pattern.matcher(allText);while (matcher.find()) {// 在输入字符串allText中查找与模式匹配的第一个子序列// 如果 提取到发票号码,则设置发票号码if (matcher.group("number") != null) {invoice.setNumber(matcher.group("number"));} else if (matcher.group("date") != null) {String rawDate = matcher.group("date"); // 发票日期,解析日期并设置日期try {SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyy年MM月dd日");SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy-MM-dd");Date parsedDate = inputDateFormat.parse(rawDate);String formattedDate = outputDateFormat.format(parsedDate);invoice.setDate(formattedDate);} catch (ParseException e) {System.out.println("无法解析日期:" + rawDate);}}// 如果没有提取到的话使用备用在进行提取if (matcher.group("number") == null) {Matcher matcher2 = patternNumber.matcher(allText);if (matcher2.find()) {invoice.setNumber(matcher2.group("number"));}}if (matcher.group("date") == null) {Matcher matcher3 = patternDate.matcher(allText);if (matcher3.find()) {String rawDate = matcher3.group("date");try {SimpleDateFormat inputDateFormat = new SimpleDateFormat("yyyyMM月dd日");SimpleDateFormat outputDateFormat = new SimpleDateFormat("yyyy-MM-dd");Date parsedDate = inputDateFormat.parse(rawDate);String formattedDate = outputDateFormat.format(parsedDate);invoice.setDate(formattedDate);} catch (Exception e) {System.out.println("无法解析日期:" + rawDate);}}}}}// 提取 金额、税额等{Pattern pattern = Pattern.compile(REGULAR_B.getRegex()); // 金额、税额提取正则,匹配形如“合计¥?金额¥?税额”的文本Matcher matcher = pattern.matcher(allText);if (matcher.find()) {try {invoice.setAmount(new BigDecimal(matcher.group("amount")));} catch (Exception e) {// 不处理}try {invoice.setTaxAmount(new BigDecimal(matcher.group("taxAmount")));} catch (Exception e) {invoice.setTaxAmount(new BigDecimal(0));}}}// 如果没有提取到,则再使用备用的正则进行提取if (null == invoice.getAmount()) {Pattern pattern = Pattern.compile(REGULAR_B_1.getRegex());Matcher matcher = pattern.matcher(fullText);if (matcher.find()) {try {invoice.setAmount(new BigDecimal(matcher.group("amount")));} catch (Exception e) {invoice.setAmount(new BigDecimal(0));}try {invoice.setTaxAmount(new BigDecimal(matcher.group("taxAmount")));} catch (Exception e) {invoice.setTaxAmount(new BigDecimal(0));}}}invoice.setTotalAmount(invoice.getAmount().add(invoice.getTaxAmount()));// 先创建一个发票备注实例Note note = new Note();// 提取发票备注信息{// 提取购方开户银行Pattern patternBuyer = Pattern.compile(REGULAR_A_NOTE_BUYER.getRegex()); // 提取备注信息Pattern patternBuyerAccount = Pattern.compile(REGULAR_A_NOTE_BUYERACCOUNT.getRegex()); // 提取备注信息Pattern patternSeller = Pattern.compile(REGULAR_A_NOTE_SELLER.getRegex()); // 提取备注信息Pattern patternSellerAccount = Pattern.compile(REGULAR_A_NOTE_SELLERACCOUNT.getRegex()); // 提取备注信息Pattern patternPayee = Pattern.compile(REGULAR_A_NOTE_PAYEE.getRegex()); // 提取备注信息Pattern patternChecker = Pattern.compile(REGULAR_A_NOTE_CHECKER.getRegex()); // 提取备注信息Matcher matcher0 = patternBuyer.matcher(allText);if (matcher0.find()) {// 如果查询到的话就设置备注信息try {note.setBuyer(new String(matcher0.group("buyer")));} catch (Exception e) {// 不处理}}Matcher matcher1 = patternBuyerAccount.matcher(allText);if (matcher1.find()) {// 如果查询到的话就设置备注信息try {note.setBuyerAccount(new String(matcher1.group("buyerAccount")));} catch (Exception e) {// 不处理}}Matcher matcher2 = patternSeller.matcher(allText);if (matcher2.find()) {// 如果查询到的话就设置备注信息try {note.setSeller(new String(matcher2.group("seller")));} catch (Exception e) {// 不处理}}Matcher matcher3 = patternSellerAccount.matcher(allText);if (matcher3.find()) {// 如果查询到的话就设置备注信息try {note.setSellerAccount(new String(matcher3.group("sellerAccount")));} catch (Exception e) {// 不处理}}Matcher matcher4 = patternPayee.matcher(allText);if (matcher4.find()) {// 如果查询到的话就设置备注信息try {note.setPayee(new String(matcher4.group("payee")));} catch (Exception e) {// 不处理}}Matcher matcher5 = patternChecker.matcher(allText);if (matcher5.find()) {// 如果查询到的话就设置备注信息try {note.setChecker(new String(matcher5.group("checker")));} catch (Exception e) {// 不处理}}}invoice.setDetail(note);return invoice;}/*** 替换字符串中的空格、全角空格、冒号和特殊空白字符为标准字符。** @param str 要进行替换的字符串* @return 替换后的字符串*/private static String replace(String str) {return str.replaceAll(" ", "").replaceAll(" ", "").replaceAll(":", ":").replaceAll(" ", "");}}

2.4 三层架构

controller

package com.example.pdf.controller;import com.example.pdf.entity.NewInvoice;
import com.example.pdf.service.InvoiceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;@RestController
@RequestMapping("/invoice")
public class InvoiceController {@AutowiredInvoiceService invoiceService;/*** @param*/
//    @PostMapping
//    public void insert() {
//        invoiceService.save();
//    }@CrossOrigin(origins = "http://localhost:8081", allowedHeaders = "*", allowCredentials = "true")@PostMapping("/upload")public ResponseEntity<Object> uploadFile(@RequestParam("file") MultipartFile file) {try {// 调用你的文件解析服务NewInvoice parsedData = invoiceService.parsePdfFile(file);// 返回解析后的数据return ResponseEntity.ok(parsedData);} catch (Exception e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error parsing file");}}}

service

service

package com.example.pdf.service;import com.example.pdf.entity.NewInvoice;
import org.springframework.web.multipart.MultipartFile;public interface InvoiceService {
//     void save();NewInvoice parsePdfFile(MultipartFile file);
}

serviceImpl

package com.example.pdf.service.impl;import com.example.pdf.entity.NewInvoice;
import com.example.pdf.mapper.InvoiceMapper;
import com.example.pdf.service.InvoiceService;
import com.example.pdf.utils.PDF;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;@Service
public class InvoiceServiceImpl implements InvoiceService {@AutowiredInvoiceMapper invoiceMapper;
//
//    @Override
//    public void save(){
//        //获得发票对象
//        InvoiceSubset invoiceSubset = extractInvoiceInformation("D:\\00-sqq\\idea\\test\\dzfp_24952000000116465179_深圳必维华法商品检定有限公司东莞分公司_20240726105216.pdf");
//        //调用mapper将发票对象存入到数据库中
//        invoiceMapper.save(invoiceSubset);
//    }/*** 调用解析文件的方法,解析上传的文件* @param file* @return*/@Overridepublic NewInvoice parsePdfFile(MultipartFile file) {NewInvoice newInvoice = PDF.parsePdfFile(file);return newInvoice;}
}

mapper

因为没有操作数据库,所以没有使用到mapper层

相关文章:

PDF发票解析并将信息回填到前端(1)后端解析PDF

文章目录 参考文章技术栈需求解析发票类型 1. 最终项目结构1.1 说明 2. 相关代码2.1 导入相应的maven依赖2.2 实体类2.3 工具类2.4 三层架构controllerservicemapper 参考文章 参考文章 技术栈 SpringBootVue 需求 本文主要是实现提取发票中的部分内容&#xff0c;并实现自…...

C++练习之插入删除

#include <iostream> #include <ctime> #include <cstring> #include<cstdlib> using namespace std;typedef struct bookInfo {char name[10];float price;int num; }BOOKINFO;// p: 结构体数组首元素地址 // n: 有效图书数量 void Print(const BOOKI…...

【LeetCode】238. 除自身以外数组的乘积

除自身以外数组的乘积 题目描述&#xff1a; 给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请…...

Excel公式与函数(运算符,计算限制,错误检查)(一)

公式 公式概念 公式 是以“”号为引导&#xff0c;用过运算符按照一定的顺序组合进行数据运算处理的等式&#xff0c;函数 则是按特定算法执行计算的产生一个或一组结果的预定义的特殊公式。 公式组成要素 公式的组成要素为“”&#xff0c;运算符&#xff0c;单元格引用&a…...

用AI助手写程序

用AI帮助写程序究竟靠不靠谱&#xff0c;下面来测试一下&#xff1a; 在文心一言中输入&#xff1a;写一个C Windows API串口通信程序。结果如下&#xff1a; #include <windows.h> #include <iostream> // 串口配置 void ConfigureCommPort(HANDLE hComm) {…...

动手学深度学习7.2 使用块的网络(VGG)-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记&#xff0c;以及对课后练习的一些思考&#xff0c;自留回顾&#xff0c;也供同学之人交流参考。 本节课程地址&#xff1a;25 使用块的网络 VGG【动手学深度学习v2】_哔哩哔哩_bilibili 本节教材地址&#xff1a;7.2. 使用…...

SolidityFoundry ERC4626

ERC4626简介 ERC4626 协议是一种用于代币化保险库的标准。 我们经常说 DeFi 是货币乐高&#xff0c;可以通过组合多个协议来创造新的协议&#xff1b; ERC4626 扩展了 ERC20 代币标准&#xff0c;旨在推动收益金库的标准化&#xff0c;它是 DeFi 乐高中的基础&#xff0c;它允…...

大模型时代的操作系统:融合 Rust 和大模型,打造 AI 操作系统

每次技术革命&#xff0c;无论是个人电脑、互联网还是移动设备&#xff0c;总是从硬件开始&#xff0c;然后演化到软件层。而操作系统是计算机系统的核心&#xff0c;没有它&#xff0c;计算机就只是一堆硬件&#xff0c;无法运行任何程序。 微软 CEO 萨蒂亚纳德拉曾将生成式 …...

【ML】为什么要做batch normlization,怎么做batch normlization

为什么要做batch normlization&#xff0c;怎么做batch normlization 1. batch normlization1.1 批量归一化是什么&#xff1a;1.2 为什么要做批量归一化&#xff1a; 2. feature normalization2.1 特征归一化是什么&#xff1a;2.2 为什么要做特征归一化&#xff1a; 3. batc…...

【C++指南】命名空间

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《C指南》 期待您的关注 目录 一、命名空间的重要性 1. C语言中没有命名空间而存在的问题 2. C引入了命名空间解决的问题 3.…...

RocketMQ Dashboard安装

RocketMQ Dashboard 是一个基于 Web 的管理工具&#xff0c;用于监控和管理 RocketMQ 集群。它提供了一个用户友好的界面&#xff0c;使管理员能够轻松地查看和操作 RocketMQ 系统中的各种组件和状态。 主要功能包括&#xff1a; 集群管理: 监控和管理 NameServer 和 Broker …...

前端web开发HTML+CSS3+移动web(0基础,超详细)——第3天

目录 一&#xff0c;列表-无序和有序的定义列表 二&#xff0c;表格-基本使用与表格结构标签 三&#xff0c;合并单元格 四&#xff0c;表单-input标签 五&#xff0c;表单-下拉菜单 六&#xff0c;表单-文本域 七&#xff0c;表单-label标签 八&#xff0c;表单-按钮 …...

认识MySQL

目录 数据库是什么呢&#xff1f;MySQL 数据库是什么呢&#xff1f; 在我们开始学习MySQL之前&#xff0c;先来了解一下&#xff0c;什么是数据库呢&#xff1f;我相信此时很多人会说是管理数据的&#xff0c;完全正确&#xff01;用数据库我们可以去存储大量的数据。我来给你…...

尚品汇-创建ES索引库(二十七)

目录&#xff1a; &#xff08;1&#xff09;商品检索功能介绍 &#xff08;2&#xff09;根据业务搭建数据结构 &#xff08;3&#xff09;nested 介绍 &#xff08;4&#xff09;搭建service-list服务 &#xff08;5&#xff09;构建实体与es mapping建立映射关系 &…...

设计模式-六大原则

概述 设计模式的六大原则是设计模式的基础&#xff0c;了解设计模式的原则&#xff0c;有利于设计模式实际应用的理解&#xff0c;在真实使用的时候&#xff0c;一般不太可能一个程序满足所有的设计模式六大原则&#xff0c;或多或少都会有违背设计模的地方&#xff0c;所以不…...

MyBatis搭建和增删改查

MyBatis是一个开源的持久层框架&#xff0c;用于处理数据库的增删改查操作。它能够将Java对象与数据库中的数据进行映射关系的配置&#xff0c;并自动生成对应的SQL语句&#xff0c;从而简化了数据库操作的编码工作。 MyBatis的核心思想是将SQL语句与Java代码分离&#xff0c;…...

【一图学技术】6.反向代理 vs API网关 vs 负载均衡的原理和使用场景

反向代理 vs API网关 vs 负载均衡 一、概念 ​ &#x1f30f;反向代理&#xff08;Reverse Proxy&#xff09;是一种位于服务器和客户端之间的代理服务器。 ​ 它接收来自客户端的请求&#xff0c;并将其转发给后端服务器&#xff0c;然后将后端服务器的响应返回给客户端。客…...

python爬虫番外篇 | Reuqests库高级用法(1)

文章目录 1.会话对象&#xff08;Session Objects&#xff09;2.请求和响应对象&#xff08;Request and Response Objects&#xff09;3.准备好的请求&#xff08;Prepared Requests&#xff09;4.SSL证书验证5.客户端证书6.CA 证书7.正文内容工作流程&#xff08;Body Conten…...

【链表OJ】常见面试题 3

文章目录 1.[环形链表II](https://leetcode.cn/problems/linked-list-cycle-ii/description/)1.1 题目要求1.2 快慢指针1.3 哈希法 2.[随机链表的复制](https://leetcode.cn/problems/copy-list-with-random-pointer/description/)2.1 题目要求2.2 迭代法 1.环形链表II 1.1 题目…...

Linux学习笔记9(Linux包管理)

目录 归档包管理 归档 查看归档包 解归档包 压缩包管理 Zip/unzip gzip/gunzip bzip2/bunzip2 源码包安装软件 三大步&#xff1a; 预备步骤&#xff1a;安装依赖的编译库 一、./configure --prefix/usr/local/nginx 二、make 三、make install 软件包安装 配置…...

论文阅读《Geometric deep learning of RNA structure》

引入了机器学习方法&#xff0c;通过少量的数据学习。只使用原子坐标作为输入。 预测RNA三维结构比预测蛋白质结构更困难。 设计了一个原子旋转等变评分器ARES&#xff0c;由每个原子的三维坐标和化学元素类型&#xff08;输入&#xff09;指定&#xff0c;ARES预测模型与未知真…...

宏集方案 | 传统建筑智能化改造,迈向物联新时代

前言 智能建筑涉及多个系统的集成&#xff0c;如照明、空调、安防等&#xff0c;这些系统的兼容性和协调运作是一大挑战。然而&#xff0c;传统的工业建筑和商业楼宇受早期设计的局限&#xff0c;多个控制系统间互不兼容&#xff0c;并且难以重新部署通信线缆。 针对传统建筑…...

如果服务器更改Web端口会减少被攻击的风险吗?

通过更改服务器的Web端口&#xff0c;是否能够显著降低被攻击的风险?首先&#xff0c;理解Web服务默认使用的端口是关键。HTTP协议通常使用80端口&#xff0c;而HTTPS则默认使用443端口。这些端口因其广泛认知而成为黑客攻击的首要目标。理论上&#xff0c;将Web服务迁移到非标…...

vim列编辑模式

在编辑文本时&#xff0c;经常会有这样的需求&#xff0c;对特定列进行进行批量编辑。比如批量注释一段代码&#xff0c;或者删除待定字符&#xff08;如一列空格&#xff09;。幸运的是VIM支持列编辑模式。 假设文本内容&#xff1a; Maximum length of a custom vocabulary…...

如何实现pxe安装部署

此实验环境&#xff1a;rhel7主机 一、kickstart自动化安装脚本 1、安装可视化图形 [rootlocalhost ~]# yum group install "Server with GUI" 2、关闭vmware dhcp功能&#xff08;编辑-虚拟网络编辑器&#xff09; 3、httpd 1、安装httpd服务 [rootlocalhost …...

机器学习常见模型

1、线性模型 线性模型是机器学习最基本的算法类型&#xff0c;它试图学到一个通过多个特征&#xff08;属性&#xff09;计算的线性组合来预测的函数&#xff0c;简单的线性回归形式如yaxb&#xff0c;其中&#xff0c;x代表特征&#xff0c;而y代表结果&#xff0c;一旦a和b的…...

【python案例】基于Python 爬虫的房地产数据可视化分析设计与实现

引言 研究背景与意义 房地产行业在我国属于支柱性产业&#xff0c;在我国社会经济发展中一直扮演着重要角色。房价问题&#xff0c;尤其是大中城市的房价问题&#xff0c;一直是政府、大众和众多研究人员关注的热点。如何科学地预测房价是房价问题的研究方向之一。随着互联网…...

如何在Python中诊断和解决内存溢出问题

python的内存溢出即程序在申请内存后未能正确释放&#xff0c;导致随着时间推移占用的内存越来越多&#xff0c;以下是一些可能导致内存溢出的原因&#xff1a; 1、循环引用&#xff1a;当对象之间形成循环引用&#xff0c;并且这些对象定义了__del__方法时&#xff0c;Python…...

什么是爬虫软件?这两个爬虫神器你必须要试试

爬虫软件概述 爬虫&#xff0c;又称为网络爬虫或网页爬虫&#xff0c;是一种自动浏览互联网的程序&#xff0c;它按照一定的算法顺序访问网页&#xff0c;并从中提取有用信息。爬虫软件通常由以下几部分组成&#xff1a; 用户代理&#xff08;User-Agent&#xff09;&#xf…...

记录|MVS和VM软件使用记录

目录 前言一、常用属性二、触发模式选择三、操作注意点四、录像、抓拍功能五、VM软件六、VM软件界面介绍七、VM软件运行间隔八、VM软件图像源九、VM软件相机管理十、获取图像十一、方案存储十一、相机拍摄彩图转换颜色转换快速匹配特征模板&#xff1a;运行参数 十二、位置修正…...