在 Windows 上将 Numpy 数组复制到剪贴板而不依赖 win32?

问题描述 投票:0回答:2

如何将 Numpy 数组粘贴到 Excel 的主要答案可以将 Numpy 数组复制到剪贴板中,准备粘贴到 Excel 中:

import numpy as np
import win32clipboard as clipboard
def toClipboardForExcel(array):
    array_string = "\r\n".join("\t".join(line.astype(str)).replace("\n","") for line in array)
    clipboard.OpenClipboard()
    clipboard.EmptyClipboard()
    clipboard.SetClipboardText(array_string)
    clipboard.CloseClipboard()
Y = np.arange(64).reshape((8, 8))
toClipboardForExcel(Y)

是否可以在没有额外的

win32
包依赖项的情况下执行此操作?(我目前在我的项目中没有使用它,我想避免仅为剪贴板添加它,注意:我不使用
 pandas
任一)

我已经尝试过使用

os.system(`echo string | clip`)
但它不适用于多行内容(包含
\n
)。

或者也许是

OpenClipboard
SetClipboardText
等可以通过
ctypes
(我已经使用过)访问?

注意:这不是将文本复制到剪贴板的Python脚本的重复项,因为后者是通用的,并且具有额外的依赖项,在我的问题中,我们希望避免新的依赖项。

python windows numpy ctypes clipboard
2个回答
3
投票

这里是一个仅限

ctypes
的示例,用于在剪贴板上设置任何 Python
str
类型的文本并将其读回。请注意,文本不应包含空值,因为
CF_UNICODETEXT
类型期望以空值结尾的文本。

import ctypes as ct
import ctypes.wintypes as w

CF_UNICODETEXT = 13
NO_ERROR = 0
SIZE_T = ct.c_size_t
GMEM_MOVEABLE = 0x0002

# Error handlers to raise exceptions on failure.

def boolcheck(result, func, args):
    if not result:
        raise ct.WinError(ct.get_last_error())

def nullcheck(result, func, args):
    if result is None:
        raise ct.WinError(ct.get_last_error())
    return result

def zeroerrorcheck(result, func, args):
    if not result:
        err = ct.get_last_error()
        if err != NO_ERROR:
            raise ct.WinError(err)
    return result

# Capture GetLastError() code after each call.
# Fully specify argtypes and restype for ctypes type-checking.

kernel32 = ct.WinDLL('kernel32', use_last_error=True)
GlobalLock = kernel32.GlobalLock
GlobalLock.argtypes = w.HGLOBAL,
GlobalLock.restype = w.LPVOID
GlobalLock.errcheck = nullcheck
GlobalAlloc = kernel32.GlobalAlloc
GlobalAlloc.argtypes = w.UINT, SIZE_T
GlobalAlloc.restype = w.HGLOBAL
GlobalAlloc.errcheck = nullcheck
GlobalUnlock = kernel32.GlobalUnlock
GlobalUnlock.argtypes = w.HGLOBAL,
GlobalUnlock.restype = w.BOOL
GlobalUnlock.errcheck = zeroerrorcheck

user32 = ct.WinDLL('user32', use_last_error=True)
OpenClipboard = user32.OpenClipboard
OpenClipboard.argtypes = w.HWND,
OpenClipboard.restype = w.BOOL
OpenClipboard.errcheck = boolcheck
GetClipboardData = user32.GetClipboardData
GetClipboardData.argtypes = w.UINT,
GetClipboardData.restype = w.HANDLE
GetClipboardData.errcheck = nullcheck
SetClipboardData = user32.SetClipboardData
SetClipboardData.argtypes = w.UINT, w.HANDLE
SetClipboardData.restype = w.HANDLE
SetClipboardData.errcheck = nullcheck
CloseClipboard = user32.CloseClipboard
CloseClipboard.argtypes = ()
CloseClipboard.restype = w.BOOL
CloseClipboard.errcheck = boolcheck
EmptyClipboard = user32.EmptyClipboard
EmptyClipboard.argtypes = ()
EmptyClipboard.restype = w.BOOL
EmptyClipboard.errcheck = boolcheck
GetForegroundWindow = user32.GetForegroundWindow
GetForegroundWindow.argtypes = ()
GetForegroundWindow.restype = w.HWND

def get_clipboard_text():
    OpenClipboard(GetForegroundWindow())
    hmem = GetClipboardData(CF_UNICODETEXT)
    pmem = GlobalLock(hmem)
    text = ct.wstring_at(pmem)
    GlobalUnlock(hmem)
    CloseClipboard()
    return text

def set_clipboard_text(text):
    ztext = text + '\x00'  # null terminator required
    OpenClipboard(None)
    EmptyClipboard()
    hmem = GlobalAlloc(GMEM_MOVEABLE, len(ztext) * ct.sizeof(w.WCHAR))
    pmem = GlobalLock(hmem)
    btext = ztext.encode('utf-16le')
    ct.memmove(pmem, btext, len(btext))
    GlobalUnlock(hmem)
    SetClipboardData(CF_UNICODETEXT, hmem)
    CloseClipboard()
    
set_clipboard_text('马克')
print(get_clipboard_text())

0
投票

我没有查看所有提供 Windows 剪贴板功能的库,但它通常不是一件非常简单的事情。 Windows 需要一些样板文件,这通常对于构建完整的 GUI 应用程序更有用。剪贴板本质上是一种用户体验,因此将其与 GUI 相关功能绑定在一起是很自然的(比如首先需要一个窗口句柄来打开剪贴板)。

如果您遇到分发挑战(即:将代码分发到非联网计算机),这使得添加 pip 依赖项变得困难,我会简单地采用具有合适许可证的现有项目并将其作为子模块复制到您的项目中。链接的重复项提到

Pyperclip
本身不需要外部依赖项即可与 Windows 一起使用,并且可以有效地执行您想要的操作(通过
ctypes
与 Windows 剪贴板交互)。

如果你确实需要自己实现,我还是会参考

Pyperclip
来了解整个过程的所有细节:

  1. 创建窗口句柄
  2. 获取剪贴板控制
  3. 为字符串分配内存
  4. 将数据从Python字符串复制到分配的内存
  5. 将数据传递到剪贴板
  6. 清理(并且不要忘记一路上的错误处理)
© www.soinside.com 2019 - 2024. All rights reserved.