Anki插件Export deck to html的改造

在Anki中进行复习时,每次只能打开一条笔记。如果积累了很多笔记,有时候会有将它们集中输出成一个pdf进行阅读的想法。Anki插件Export deck to html(安装ID:1897277426)就有这个功能。但是,这个插件目前存在以下问题:

1、Anki升级为版本 ⁨24.06.3 (d678e393)⁩后(也许更早的版本就这样,我没试过),插件无法正常运行;

2、插件转pdf的效果不是很好,但转html的效果不错。考虑到html转pdf非常容易(word即可完成,多数浏览器在插件支持下或无需插件也能完成),所以插件的转pdf功能比较鸡肋;

3、笔记中的img标签,在转换为html后,除了“src”属性得以保留,其余的属性会全部丢失。

4、输出的html在每一条笔记前添加了没有用处的前缀“>y”

鉴于上述问题,所以对该插件的主文件ExportDeckToHtml.py进行了修改。具体修改的内容包括:

1、将不在兼容新版Anki的几行代码进行修改和删除,其中包括

1)dialog.exec_()修改为dialog.exec()

2)options = QFileDialog.DontUseNativeDialog删除

3)path = QFileDialog.getSaveFileName( self, "Save File", directory, "All Files (*)", options=options) 修改为path = QFileDialog.getSaveFileName(  self, "Save File", directory, "All Files (*)")

2、修改_setup_ui函数,取消界面上的保存为pdf等元素。

3、修改_export_to_html函数,在处理卡片的html中的img标签时,只将src属性中的路径修改为绝对路径,而src属性之外的其他属性保持不变。

4、修改每条笔记的html,增加笔记序号信息,删掉无用前缀。

修改后的ExportDeckToHtml.py文件内容如下:

from aqt import mw, utils
from aqt.qt import *
from os.path import expanduser, join
from pickle import load, dump

import os
import re
import unicodedata
from .pdfkit import from_string

delimiter = "####"

ascending = "Ascending"
descending = "Descending"
config_file = "export_decks_to_html_config.cfg"


class AddonDialog(QDialog):

    """Main Options dialog"""

    def __init__(self):
        global config_file
        QDialog.__init__(self, parent=mw)
        self.path = None
        self.deck = None
        self.fields = {}
        self.card_orders = [ascending, descending]
        self.order_fn = None
        self.advance_mode = False
        if os.path.exists(config_file):
            try:
                self.config = load(open(config_file, 'rb'))
            except:
                self.config = {}
        else:
            self.config = {}
        self._setup_ui()

    def _handle_button(self):
        dialog = OpenFileDialog()
        self.path = dialog.filename
        if self.path is not None:
            utils.showInfo("Choose file successful.")

    def _handle_load_template(self):
        dialog = OpenFileDialog()
        self.advance_mode = False
        self.template_path = dialog.filename
        if self.template_path is not None and len(self.template_path) > 0:
            utils.showInfo("Choose file successful.")
            self.template_label.setText(self.template_path)

    def _setup_ui(self):
        """Set up widgets and layouts"""
        layout = QGridLayout()
        layout.setSpacing(10)

        deck_label = QLabel("Choose deck")

        # deck name
        self.deck_selection = QComboBox()
        deck_names = sorted(mw.col.decks.allNames())
        current_deck = mw.col.decks.current()['name']
        deck_names.insert(0, current_deck)
        for i in range(len(deck_names)):
            if deck_names[i] == 'Default':
                deck_names.pop(i)
                break
        self.deck_selection.addItems(deck_names)
        self.deck_selection.currentIndexChanged.connect(self._select_deck)
        layout.addWidget(deck_label, 1, 0, 1, 1)
        layout.addWidget(self.deck_selection, 1, 1, 1, 2)

        export_dir = self.config.get('export_dir', expanduser("~/Desktop"))
        self.export_dir = QLineEdit(export_dir)

        field_label = QLabel('Sort')
        self.field_selection = QComboBox()
        fields = self._select_fields(self.deck_selection.currentText())
        if self.deck_selection.currentText() in self.config:
            currentField = self.config[self.deck_selection.currentText()].get(
                'field_selection', '')
            if len(currentField) > 0:
                if currentField in fields:
                    fields.remove(currentField)
                    fields.insert(0, currentField)
        self.field_selection.addItems(fields)

        layout.addWidget(field_label, 2, 0, 1, 1)
        layout.addWidget(self.field_selection, 2, 1, 1, 2)

        template_path = ''
        if self.deck_selection.currentText() in self.config:
            template_path = self.config[self.deck_selection.currentText()].get(
                'template_path', '')

        self.template_label = QLabel(template_path)

        # order
        order_label = QLabel('Order')
        self.order_selection = QComboBox()
        orders = self.card_orders[:]
        if self.deck_selection.currentText() in self.config:
            currentOrder = self.config[self.deck_selection.currentText()].get(
                "order_selection", '')
            if len(currentOrder) > 0:
                orders.remove(currentOrder)
                orders.insert(0, currentOrder)

        self.order_selection.addItems(orders)

        self.order_selection.currentIndexChanged.connect(
            self._handle_order_card)
        layout.addWidget(order_label, 3, 0, 1, 1)
        layout.addWidget(self.order_selection, 3, 1, 1, 2)

        self.load_template_btn = QPushButton('Load template')
        self.load_template_btn.clicked.connect(self._handle_load_template)

        layout.addWidget(self.load_template_btn, 4, 0, 1, 1)
        layout.addWidget(self.template_label, 4, 1, 1, 2)

        self.to_pdf = False
        layout.addWidget(self.export_dir, 5, 1, 1, 2)
        export_dir_label = QLabel("Export directory")
        layout.addWidget(export_dir_label, 5, 0, 1, 1)

        # Main button box
        ok_btn = QPushButton("Export")
        save_btn = QPushButton("Save")
        cancel_btn = QPushButton("Cancel")

        button_box = QHBoxLayout()
        ok_btn.clicked.connect(self._on_accept)
        save_btn.clicked.connect(self._on_save)
        cancel_btn.clicked.connect(self._on_reject)
        button_box.addWidget(ok_btn)
        button_box.addWidget(save_btn)
        button_box.addWidget(cancel_btn)

        # Main layout
        main_layout = QVBoxLayout()
        main_layout.addLayout(layout)
        main_layout.addLayout(button_box)
        self.setLayout(main_layout)
        self.setMinimumWidth(360)
        self.setWindowTitle('Export deck to html')

    def _reset_advance_mode(self):
        self.advance_mode = False
        self.csv_file_label.setText('')

    def _to_pdf(self):
        self.to_pdf = not self.to_pdf

    def _handle_adv_mode(self):
        dialog = OpenFileDialog("csv")
        self.path = dialog.filename
        if self.path is not None and len(self.path) > 0:
            utils.showInfo("Choose file successful.")
            self.advance_mode = True
            self.csv_file_label.setText(self.path)

    def _select_deck(self):
        current_deck = self.deck_selection.currentText()

        fields = self._select_fields(current_deck)
        if self.deck_selection.currentText() in self.config:
            currentField = self.config[current_deck].get('field_selection', '')
            if len(currentField) > 0:
                fields.remove(currentField)
                fields.insert(0, currentField)
        self.field_selection.clear()
        self.field_selection.addItems(fields)

        orders = self.card_orders[:]
        if current_deck in self.config:
            currentOrder = self.config[current_deck].get("order_selection", '')
            if len(currentOrder) > 0:
                orders.remove(currentOrder)
                orders.insert(0, currentOrder)
        self.order_selection.clear()
        self.order_selection.addItems(orders)

        template_path = ''
        if current_deck in self.config:
            template_path = self.config[current_deck].get("template_path", '')
        self.template_label.setText(template_path)

    def _on_save(self):
        global config_file
        current_deck = self.deck_selection.currentText()
        self.config[current_deck] = {}
        self.config[current_deck]['template_path'] = self.template_label.text()
        self.config[current_deck]["field_selection"] = self.field_selection.currentText()
        self.config[current_deck]["order_selection"] = self.order_selection.currentText()
        self.config[current_deck]["to_pdf"] = self.to_pdf
        self.config["export_dir"] = self.export_dir.text()
        dump(self.config, open(config_file, 'wb'))
        utils.showInfo("Config saved")

    def _convert_to_multiple_choices(self, value):
        choices = value.split("|")
        letters = "ABCDEFGHIKLMNOP"
        value = "<div>"
        for letter, choice in zip(letters, choices):
            value += '<div>' + \
                "<span><strong>(" + letter + ")&nbsp</strong></span>" + \
                choice.strip() + '</div>'
        return value + "</div>"

    def _select_fields(self, deck):
        query = 'deck:"{}"'.format(deck)
        try:
            card_id = mw.col.findCards(query=query)[0]
        except:
            utils.showInfo("This deck has no cards.")
            return []

        card = mw.col.getCard(card_id)
        fields = card.note().keys()
        return ["Due", ] + fields

    def _handle_order_card(self):
        self.order_fn = self._order_card(self.order_selection.currentText())

    def _order_card(self, order_by):
        def f(field):
            def g(card):
                try:
                    if field == 'Due':
                        return card.due
                    return card.note()[field]
                except KeyError:
                    return ''

            return g

        def ascending_fn(cards, field):
            return sorted(cards, key=f(field))

        def descending_fn(cards, field):
            return sorted(cards, key=f(field), reverse=True)

        if order_by == ascending:
            return ascending_fn

        return descending_fn

    def _get_all_cards(self, deck_name, field, order_fn):
        deck_name = deck_name.replace('"', '')
        deck_name = unicodedata.normalize('NFC', deck_name)
        deck = mw.col.decks.byName(deck_name)
        if deck == None:
            return

        decks = [deck_name, ]
        if len(mw.col.decks.children(deck['id'])) != 0:
            decks = [name for (name, _) in mw.col.decks.children(deck['id'])]

        decks = sorted(decks)
        all_cards = []
        for deck in decks:
            query = 'deck:"{}"'.format(deck)
            cids = mw.col.findCards(query=query)
            cards = []
            for cid in cids:
                card = mw.col.getCard(cid)
                cards.append(card)

            all_cards.extend(cards)

        if order_fn is not None:
            return order_fn(all_cards, field)

        return all_cards


    def _export_to_html(self, output_path, deck_name, sort_by, order, template_path, export_to_pdf=True):
        # html_path = self.template_label.text()
        if template_path is None or len(template_path) == 0:
            return False

        order_fn = self._order_card(order)
        cards = self._get_all_cards(deck_name, sort_by, order_fn)
        if cards is None or len(cards) == 0:
            return False

        html_template = ''
        with open(template_path, 'r', encoding='utf-8') as f:
            html_template += f.read()

        header, body, has_table = self._separate_header_and_body(
            html_template)

        collection_path = mw.col.media.dir()

        path = output_path
        try:
            html = ""
            template = body
            fields = re.findall("\{\{[^\}]*\}\}", template)
            dedup = set()
            for i, card in enumerate(cards):
                card_html = template
                card_html = card_html.replace("{{id}}", str(i + 1))
                key = ""
                for field in fields:
                    if field == "{{id}}":
                        continue
                    try:
                        value = card.note()[field[2:-2]]
                        key += value
                    except KeyError:
                        value = '## field ' + field + ' not found ##'

                    card_html = card_html.replace(field, value)
                # 将html中的相对路径全部替换为绝对路径
                pattern = re.compile(r'<img.*?src="(.*?)".*?>', re.I | re.M)
                for match in re.finditer(pattern, card_html):
                    relative_path = match.group(1)
                    absolute_path = f'{collection_path}\\{relative_path}'
                    card_html = card_html.replace(relative_path, absolute_path)

                if key not in dedup:
                    html += '<span class="red">第' + str(i + 1) + '条:</span>' + card_html[2:]
                    dedup.add(key)

            if not has_table:
                html = header + "\n<body>" + html + "</body>"
            else:
                html = header + "\n<body>\n\t<table>" + html + "\t</table>\n</body>"
            if not export_to_pdf:
                with open(path, "w", encoding="utf8") as f:
                    f.write(html)
            else:
                options = {
                    # 'header-left': '[webpage]',
                    # 'header-right': '[page]/[toPage]',
                    # 'header-line': '',
                    # 'header-font-size': 10
                    'margin-bottom': 15,
                    'margin-left': 10,
                    'margin-right': 10,
                    'margin-top': 15,
                    'footer-center': '[page]',
                    'footer-font-size': 8,
                    'footer-spacing': 5,
                }
                from_string(html, path, options)
        except IOError as e:
            return False
        return True

    def _on_accept(self):
        if not self.advance_mode:
            dialog = SaveFileDialog(
                self.deck_selection.currentText(), self.export_dir.text(), self.to_pdf)
            file_path = dialog.filename
            if file_path == None:
                return

            if type(file_path) is tuple:
                file_path = file_path[0]

            template_path = self.template_label.text()
            if template_path is None or len(template_path) == 0:
                utils.showInfo("Cannot find template")
                return

            can_export = self._export_to_html(join(self.export_dir.text(), file_path),
                                              self.deck_selection.currentText(),
                                              self.field_selection.currentText(),
                                              self.order_selection.currentText(),
                                              template_path,
                                              self.to_pdf)
            if not can_export:
                utils.showInfo("Cannot export")
            else:
                utils.showInfo("Exported successfully")
        else:
            with open(self.path, "r", encoding="utf-8") as f:
                i = 0
                non_exist_decks = []
                non_exist_files = []
                for line in f:
                    if i == 0:
                        i += 1
                        continue

                    deck_name, output_dir, output_name, sort_by, order, template_path, to_pdf = \
                        line.split(',')[:7]
                    if output_name is None and len(output_name) == 0:
                        output_name = deck_name

                    if not os.path.isfile(template_path):
                        non_exist_files.append(template_path)
                        continue

                    to_pdf = True if standardize(
                        to_pdf).lower() == 'true' else False
                    can_export = self._export_to_html(
                        join(standardize(output_dir),
                             standardize(output_name)),
                        standardize(deck_name),
                        standardize(sort_by),
                        standardize(order),
                        standardize(template_path),
                        to_pdf)
                    if not can_export:
                        non_exist_decks.append(deck_name)

                if len(non_exist_decks) > 0:
                    utils.showInfo("Non existing decks\n" +
                                   '\n'.join(non_exist_decks))
                    return

                if len(non_exist_files) > 0:
                    utils.showInfo("Non existing files\n" +
                                   '\n'.join(non_exist_files))
                    return

                utils.showInfo("Exported successfully")

    def _on_reject(self):
        self.close()

    def _separate_header_and_body(self, hl):
        last_header = hl.find("</head>")
        last_header += len("</head>")
        body = hl[last_header:]
        first = body.find("<table>")
        last = body.rfind("</table>")
        if first == -1 or last == -1:
            first = body.find("<table>") + len("<body>")
            last = body.find("</body>")
            has_table = False
        else:
            first = first + len("<table>")
            has_table = True

        return hl[:last_header][:], body[first:last], has_table


class SaveFileDialog(QDialog):
    def __init__(self, filename, export_dir=expanduser("~/Desktop/"), to_pdf=False):
        QDialog.__init__(self, mw)
        self.title = 'Save File'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self.filename = None
        self.default_filename = filename
        self.to_pdf = to_pdf
        self.export_dir = export_dir
        self._init_ui()

    def _init_ui(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.filename = self._get_file()

    def _get_file(self):
        # options = QFileDialog.Options()
        # 升级后QFileDialog不存在DontUseNativeDialog属性
        # options = QFileDialog.DontUseNativeDialog
        default_filename = self.default_filename.replace('::', '_')
        if not self.to_pdf:
            directory = join(self.export_dir, default_filename + ".html")
        else:
            directory = join(self.export_dir, default_filename + ".pdf")

        try:
            path = QFileDialog.getSaveFileName(
                    # 取消options参数
                    # self, "Save File", directory, "All Files (*)", options=options)
                    self, "Save File", directory, "All Files (*)")
            if path:
                return path
            else:
                utils.showInfo("Cannot open this file.")
        except:
            utils.showInfo("Cannot open this file.")
        return None


class OpenFileDialog(QDialog):
    def __init__(self, file_type="html"):
        QDialog.__init__(self, mw)
        self.title = 'Open file'
        self.left = 10
        self.top = 10
        self.width = 640
        self.height = 480
        self.filename = None
        self.file_type = file_type
        self._init_ui()

    def _init_ui(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.filename = self._get_file()
        # self.exec_()

    def _get_file(self):
        # options = QFileDialog.Options()
        # 升级后QFileDialog不存在DontUseNativeDialog属性
        # options = QFileDialog.DontUseNativeDialog
        directory = expanduser("~/Desktop")
        try:
            if self.file_type == "html":
                path = QFileDialog.getOpenFileName(
                    # 取消options参数
                    # self, "Save File", directory, "All Files (*)", options=options)
                    self, "Save File", directory, "All Files (*)")
            elif self.file_type == "csv":
                path = QFileDialog.getOpenFileName(
                    # 取消options参数
                    # self, "Save File", directory, "All Files (*)", options=options)
                    self, "Save File", directory, "All Files (*)")
            if path and path[0]:
                return path[0]
            else:
                utils.showInfo("Cannot open this file.")
        except:
            utils.showInfo("Cannot open this file.")
            return None


def display_dialog():
    dialog = AddonDialog()
    dialog.exec()
    # 原来方法名exec_错误,多了下划线
    # dialog.exec_()


def standardize(word):
    return word.strip()


action = QAction("Export deck to html", mw)
action.setShortcut("Ctrl+M")
action.triggered.connect(display_dialog)
mw.form.menuTools.addAction(action)

只需安装该插件,然后打开插件文件夹,编辑ExportDeckToHtml.py文件,将其内容全部替换为以上代码即可。在使用此插件时,需要提前准备一个html模板。我用于导出基于对兼容各操作系统的Anki选择题模板的更新——提供更方便的笔记修改功能-CSDN博客一文中的模板所编写的笔记牌组的html模板如下,可供参考:

<!DOCTYPE html>
<html>
<head>
   
    <style>
     body{
    	font-size:1.2em;
    	width:19.7cm;
    }
        table {
	border-collapse: collapse;
}

table tr:nth-child(2n+1) {
	background-color: #eee;
}

td {
	padding: 5px;
	text-align: center;
	border: 2px solid green;
	vertical-align: middle;
}

td.left {
	text-align: left;
}

td.red {
	border-right: solid thick red;
}

hr {
	border: none;
	height: 5px;
	background-color: blue;
}

div {
	margin: 5px auto
}


a,
a:visited,
a:hover,
a:link,
a:active {
	color: #f90;
	font-weight: bold;
	font-family:Cambria-modify,'干就完事了简','微软雅黑';
}

.pink{
	font-family:'黑体';
	font-weight: bold;
	font-size: 1.2em;
}

u,
.red {
	color: #f00;
	font-weight: bold;
	text-decoration: none;
	font-family:Cambria-modify,'干就完事了简','微软雅黑';
}

.green,
i {
	font-weight: bold;
	font-style: normal;
	color: #3bb;
	font-family:Cambria-modify,'Aa奇思胖丫儿','微软雅黑';
}

.blue,
b {
	font-weight: bold;
	font-style: normal;
	color: #39e;
	font-family:Cambria-modify,'微软雅黑';
}

img{
	display:block;
	object-fit:scale-down;
}
    </style>
</head>
<body>
<div><span class='pink'>【题干】:</span>{{问题}}</div>
<span class='pink'>【选项】:</span>
<div>{{选项}}</div>
<div><span class='pink'>【答案】:</span>{{答案}}</div>
<span class='pink'>【解析】:</span>
<div>{{解析}}</div>
<hr>
</body>
</html>

基于以上模板输出html的操作过程如下:

c5cf3120ad0e498f8172b546a2185c32.png

6f7871eeeddf4dcea9ea5eedcfbeff2c.png

导出的html效果如下:

58343782896b44b6b93df542c396da97.png

顺便说一句,在试用了十数个Anki插件后,我只保留了两个:Edit field during review和Export deck to html。如果有其他便于Anki使用的插件,欢迎留言推荐,如有改造相关插件的想法,也欢迎留言,我可能会试着帮你实现。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/903237.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

哈希表——unordered_set和unordered_map的封装

个人主页&#xff1a;敲上瘾-CSDN博客 个人专栏&#xff1a;游戏、数据结构、c语言基础、c学习、算法 在本章关于哈希表的设计在这里就随便提一点不再过多的讲解&#xff0c;而把重点放在封装部分。 目录 一、哈希表的设计 1.模板参数的设计 二、迭代器封装 1.迭代器简单…

理解计算机系统_异常控制流(一):异常

前言 以<深入理解计算机系统>(以下称“本书”)内容为基础&#xff0c;对程序的整个过程进行梳理。本书内容对整个计算机系统做了系统性导引,每部分内容都是单独的一门课.学习深度根据自己需要来定 引入 异常控制流这章实际上是操作系统的一部分.操作系统简单的…

驱动学习(三)符号导出

1.什么是符号&#xff1f; 主要是指全局变量和函数 2.为什么要导出符号&#xff1f; ​ linux内核采用的是模块化的形式管理内核代码。内核中每个模块之间是相互独立的&#xff0c;也就是说A模块的全局变量和函数&#xff0c;B模块是无法访问的。若B模块想要使用A模块中的已有…

python爬虫——Selenium的基本使用

目录 一、Selenium的介绍 二、环境准备 1.安装Selenium 2.安装WebDriver 三、元素定位 1.常用定位元素的方法 2. 通过指定方式定位元素 四、窗口操作 1.最大化浏览器窗口 2.设置浏览器窗口大小 3.切换窗口或标签页 切换回主窗口 4. 关闭窗口 关闭当前窗口 关闭所…

java_方法重载、可变参数、作用域

方法重载 基本介绍 java 中允许同一个类中&#xff0c;多个同名方法的存在&#xff0c;但要求 形参列表不一致&#xff01; 比如&#xff1a;System.out.println(); out 是 PrintStream 类型 重载的好处 减轻了起名的麻烦减轻了记名的麻烦 案例 public class OverLoad01 …

SCI一区级 | Matlab实现SSA-TCN-LSTM-Attention多变量时间序列预测

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.基于SSA-TCN-LSTM-Attention麻雀搜索算法优化时间卷积长短期记忆神经网络融合注意力机制多变量时间序列预测&#xff0c;要求Matlab2023版以上&#xff0c;自注意力机制&#xff0c;一键单头注意力机制替换成多头注…

leetcode刷题(76-80)

算法是码农的基本功&#xff0c;也是各个大厂必考察的重点&#xff0c;让我们一起坚持写题吧。 遇事不决&#xff0c;可问春风&#xff0c;春风不语&#xff0c;即是本心。 我们在我们能力范围内&#xff0c;做好我们该做的事&#xff0c;然后相信一切都事最好的安排就可以啦…

深度生成模型 - 受限玻尔兹曼机(RBM)篇

前言 受限玻尔兹曼机&#xff08; Restricted Boltzmann Machine&#xff0c;RBM \text{Restricted Boltzmann Machine&#xff0c;RBM} Restricted Boltzmann Machine&#xff0c;RBM&#xff09;是深度学习领域中的一种重要模型&#xff0c;其起源于统计物理学&#xff0c;由…

【再谈设计模式】单例模式~唯一性的守护者

一、引言 在软件工程中&#xff0c;软件开发&#xff0c;设计模式是提高代码复用性和可维护性的有效工具。单例模式&#xff08;Singleton Pattern&#xff09;作为一种创建型设计模式&#xff0c;旨在确保一个类只有一个实例&#xff0c;并提供对该实例的全局访问。这一模式在…

如何在 Elasticsearch Ruby 客户端中使用 ES|QL Helper

作者&#xff1a;来自 Elastic Fernando Briano 了解如何使用 Elasticsearch Ruby 客户端编写 ES|QL 查询并处理其结果。 简介 Elasticsearch Ruby 客户端可用于编写 EQ|QL 查询&#xff0c;使处理从 esql.query 返回的数据更加容易。ES|QL 允许开发人员通过查询过滤、转换和分…

redis详细教程(3.ZSet,Bitmap,HyperLogLog)

ZSet Redis 的 ZSet&#xff08;有序集合&#xff09;是一种特殊的数据类型&#xff0c;它允许存储一系列不重复的字符串元素&#xff0c;并为每个元素关联一个分数&#xff08;score&#xff09;。这个分数用于对集合中的元素进行排序。ZSet 的特点是&#xff1a; 唯一性&am…

MYSQL-SQL-03-DQL(Data Query Language,数据查询语言)(单表查询)

DQL&#xff08;数据查询语言&#xff09; DQL英文全称是Data Query Language(数据查询语言)&#xff0c;数据查询语言&#xff0c;用来查询数据库中表的记录。 查询关键字: SELECT 在一个正常的业务系统中&#xff0c;查询操作的频次是要远高于增删改的&#xff0c;当我们去访…

Cisco Packet Tracer 8.0 路由器的基本配置和Telnet设置

文章目录 构建拓扑图配置IP地址配置路由器命令说明测试效果 构建拓扑图 1&#xff0c;添加2811路由器。 2&#xff0c;添加pc0。 3&#xff0c;使用交叉线连接路由器和pc&#xff08;注意线路端口&#xff09;。 4&#xff0c;使用配置线连接路由器和pc&#xff08;注意线路…

优化网站结构提升用户体验的关键要素

内容概要 在数字时代&#xff0c;网站的架构和用户体验密切相关。一个合理的网站结构不仅能帮助用户快速找到所需信息&#xff0c;还能提升整体的访问满意度。为了达到这一目的&#xff0c;网站需要强调几个关键要素。 首先&#xff0c;清晰的导航设计至关重要。导航应当直观…

Android Gradle

#1024程序员节&#xff5c;征文# Gradle 是一款强大的自动化构建工具&#xff0c;广泛应用于 Android 应用开发。它通过灵活的配置和丰富的插件系统&#xff0c;为项目构建提供了极大的便利。本文只是简单的介绍 Gradle 在 Android 开发中的使用&#xff0c;包括其核心概念、构…

微积分复习笔记 Calculus Volume 1 - 3.8 Implicit Differentiation

3.8 Implicit Differentiation - Calculus Volume 1 | OpenStax

Java——lambda表达式和StreamAPI

一、lambda 1. lambda表达式 1.1 Lambda表达式的使用举例: (o1,02)->Integer.compare(o1,o2); 1.2 Lambda表达式的格式举例: Lambda形参列表->lambda 1.3 Lambda表达式的格式 lambda操作符或箭头操作符 的左边:lambda形参列表&#xff0c;对应着要重写的接口中的…

django游戏门户系统

想做毕业设计但还没有头绪&#xff1f;&#x1f64b;‍♂️django游戏门户系统了解一下&#xff01;这个系统不仅功能全面&#xff0c;还能轻松解决你的项目选题难题&#xff01; 我们这个基于Django开发的游戏门户系统提供了用户注册、登录、内容发布以及管理功能&#xff0c…

大数据日志处理框架ELK方案

介绍应用场景大数据ELK日志框架安装部署 一&#xff0c;介绍 大数据日志处理框架ELK&#xff08;Elasticsearch、Logstash、Kibana&#xff09;是一套完整的日志集中处理方案&#xff0c;以下是对其的详细介绍&#xff1a; 一、Elasticsearch&#xff08;ES&#xff09; 基本…

【SQL实验】表的更新和简单查询

完整代码在文章末尾 在上次实验创建的educ数据库基础上&#xff0c;用SQL语句为student表、course表和sc表中添加以下记录 【SQL实验】数据库、表、模式的SQL语句操作_创建一个名为educ数据库,要求如下: (下面三个表中属性的数据类型需要自己设计合适-CSDN博客在这篇博文中已经…