leerzeichen nach URL

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
brainstir
User
Beiträge: 25
Registriert: Dienstag 26. September 2017, 08:36

Freitag 7. September 2018, 21:08

hallo,

ich füge einen text mit autokey ein.
Ich muss nun den text den ich einfügen möchte nach URLs durchsuchen und nach der URL ein Leerzeichen senden, dann den restlichen text (mit lerrezichen nach einer url, falls da noch mehr urls sind etc.)
aktuell bin Ich so weit:

Code: Alles auswählen

import re
import time
a_string = 'test of testing https://www.one.com with another test https://two.com part3 http://three.com last test'
urls = re.findall('https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+', a_string)
split_string = a_string.split(urls[0])
text = (f'{split_string[0]} {urls[0]} {split_string[1]}')

x=0
for url in urls:
    clipboard.fill_clipboard(f'{split_string[0]}')
    keyboard.send_keys("<ctrl>+v")
    time.sleep(0.5)
    clipboard.fill_clipboard(f'{urls[x]}')
    keyboard.send_keys("<ctrl>+v")
    time.sleep(0.5)
    keyboard.send_keys(" ")
    time.sleep(0.5)
    split_string = (f'{split_string[x+1]}').split(f'urls[x]')
    x=x+1
Als output bekomme Ich nun

Code: Alles auswählen

 test of testing https://www.one.com  with another test https://two.com part3 http://three.com last testhttps://two.com  
Aber

Code: Alles auswählen

with another test https://two.com part3 http://three.com last test
wird als ein string eingefügt...
Ich schätze Ich mache da irgendwas mit dem indexing falsch, kann mir jemand helfen?
Sirius3
User
Beiträge: 8414
Registriert: Sonntag 21. Oktober 2012, 17:20

Freitag 7. September 2018, 21:33

Dafür nimmt man re.split:

Code: Alles auswählen

parts = re.split('(https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+)', a_string)
for part in parts:
    clipboard.fill_clipboard(part)
    keyboard.send_keys("<ctrl>+v")
    time.sleep(0.5)
brainstir
User
Beiträge: 25
Registriert: Dienstag 26. September 2017, 08:36

Samstag 8. September 2018, 23:20

Damit bekomme Ich ein Space nach jedem Teil:

Code: Alles auswählen

test of testing 
SPACE
https://www.one.com
SPACE
 with another test 
SPACE
https://two.com
SPACE
 part3 
SPACE
http://three.com
SPACE
 last test
SPACE
Wie kann Ich die Leertaste nur nach den URLs senden?
Sirius3
User
Beiträge: 8414
Registriert: Sonntag 21. Oktober 2012, 17:20

Sonntag 9. September 2018, 10:39

Indem Du nur jedes zweite Mal ein SPACE sendest?
brainstir
User
Beiträge: 25
Registriert: Dienstag 26. September 2017, 08:36

Sonntag 9. September 2018, 11:50

Ok, also so funktioniert es:

Code: Alles auswählen

#!/usr/bin/python3
import time
import re
try:
    cp_altes_clipboard = clipboard.get_clipboard()
except Exception:
    pass


fragen = '''abc
test of testing https://www.one.com with another test https://two.com part3 http://three.com last test'''


parts = re.split('(https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+)', fragen)
for index, part in enumerate(parts):
    clipboard.fill_clipboard(part)
    keyboard.send_keys("<ctrl>+v")
    if (index % 2 != 0): #odd
        time.sleep(0.2)
        keyboard.send_keys(" ") #send space after second string (URL)
    time.sleep(0.3)

try:
    clipboard.fill_clipboard("%s" % cp_altes_clipboard)
except Exception:
    clipboard.fill_clipboard("")
Ich würde das ganze gerne in eine andere .py-datei packen und ich meiner eigentlichen dann nur noch den text angeben:

Code: Alles auswählen

import neue_datei.py
fragen = '''abc
test of testing https://www.one.com with another test https://two.com part3 http://three.com last test'''
Wie kann ich dem o.g. Script in neue_datei.py sagen, dass er den inhalt der fragen-variable benutzen soll?

Ich benutze das ganze in Autokey.

Ich glaube
keyboard.send_keys()
und
clipboard.fill_clipboard
sind Autokey-spezifisch.
Wie würde Ich das in python3 schreiben, weil wenn Ich die Datei in Autokey importiere, führt er die ja als Python3 und nicht mit den Autokey-bibliotheken aus, oder?
Zuletzt geändert von brainstir am Sonntag 9. September 2018, 12:12, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 8414
Registriert: Sonntag 21. Oktober 2012, 17:20

Sonntag 9. September 2018, 11:53

Wenn man einen Index braucht, nimmt man enumerate:

Code: Alles auswählen

for index, part in enumerate(parts):
    print(part)
    #keyboard.send_keys("<ctrl>+v")
    if index % 2:
        print('SPACE')
    time.sleep(0.5)
brainstir
User
Beiträge: 25
Registriert: Dienstag 26. September 2017, 08:36

Sonntag 9. September 2018, 12:26

Ja, habs gerade selbst gefunden :)

Wie kann Ich das ganze jetzt in eine neue datei.py packen
und in der eigentlichen datei dann nur noch
import neue datei.py
fragen ='''
Hier
ist
mein
Text'''
setzen?

Ich benutze das ganze in Autokey.

Ich glaube
keyboard.send_keys()
und
clipboard.fill_clipboard
sind Autokey-spezifisch.
Wie würde Ich das in python3 schreiben, weil wenn Ich die Datei in Autokey importiere, führt er die ja als Python3 und nicht mit den Autokey-bibliotheken aus, oder?
Benutzeravatar
__blackjack__
User
Beiträge: 1226
Registriert: Samstag 2. Juni 2018, 10:21

Sonntag 9. September 2018, 12:52

@brainstir: Du müsstest den Code in eine Funktion packen, die man dann importieren und mit `fragen` als Argument aufrufen kann.

Code: Alles auswählen

from neues_modul import die_funktion
FRAGEN = '''
Hier
ist
mein
Text'''

die_funktion(FRAGEN)
Statt `neues_modul` und `die_funktion` natürlich Namen die passender sind und dem Leser vermitteln was jeweiligen Objekte bedeuten.
“Pets are always a great help in times of stress. And in times of starvation too, o'course.” — Terry Pratchett, Small Gods
brainstir
User
Beiträge: 25
Registriert: Dienstag 26. September 2017, 08:36

Montag 10. September 2018, 16:15

@blackjack:

Also Ich habe jetzt folgendes in meiner .py, die ich importiere:

Code: Alles auswählen

import subprocess
import time
import sys
import os
import re
    def getClipboardData():
        p = subprocess.Popen(['xclip','-selection', 'clipboard', '-o'], stdout=subprocess.PIPE)
        retcode = p.wait()
        data = p.stdout.read()
        return data

    def setClipboardData(data):
        p = subprocess.Popen(['xclip','-selection','clipboard'], stdin=subprocess.PIPE)
        p.stdin.write(data)
        p.stdin.close()
        retcode = p.wait()

def einfuegen(fragen):
    try:
        cp_altes_clipboard = getClipboardData()
    except Exception:
        pass
    parts = re.split('(https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+)', fragen)
    for index, part in enumerate(parts):
        setClipboardData(part)
        keyboard.send_keys("<ctrl>+v")
        if (index % 2 != 0): #odd
            time.sleep(0.2)
            keyboard.send_keys(" ") #send space after second string (URL)
        time.sleep(0.3)
    try:
        setClipboardData("%s" % cp_altes_clipboard)
    except Exception:
        setClipboardData("")
Und wenn Ich das skript importiere und, dann wie von dir vorgeschlagen aufrufe, bekomme Ich diesen Fehler:

in einfuegen:
parts = re.split('(https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+)', fragen)
in split
return_compile(pattern, flags).split(string, maxsplit)
TypeError: cannot use a string pattern on a byte-like object

Ich schätze ich muss da jetzt noch irgendwo .encode() einfügen, aber wo genau?

Edit:
Wobei Ich das in dem eigentlichen skript eigentlich schon mache:

Code: Alles auswählen

#!/usr/bin/python3
from clipb import einfuegen

fragen = '''abc
test of testing https://www.one.com with another test https://two.com part3 http://three.com last test'''

einfuegen(fragen.encode())
Benutzeravatar
__blackjack__
User
Beiträge: 1226
Registriert: Samstag 2. Juni 2018, 10:21

Montag 10. September 2018, 17:38

@brainstir: Wenn `fragen` Bytes sind, dann muss auch der reguläre Ausdruck als Bytes angeben werden. Oder beides müssen Zeichenketten sein. Muss halt zusammen passen.
“Pets are always a great help in times of stress. And in times of starvation too, o'course.” — Terry Pratchett, Small Gods
brainstir
User
Beiträge: 25
Registriert: Dienstag 26. September 2017, 08:36

Montag 10. September 2018, 20:53

@blackjack

und wie mache Ich das?
Was ist denn davon Bytes und was ist String? Wo sehe Ich das?
Ich habe nicht viel Erfahrung mit Python.
Ich weiss nur, dass Ich so ein Problem vorher auch hatte und als Ich dann statt fragen fragen.encode() benutzt ha be, ging es.
Wo muss das da genau hin?
Benutzeravatar
__blackjack__
User
Beiträge: 1226
Registriert: Samstag 2. Juni 2018, 10:21

Montag 10. September 2018, 21:14

Das hier 'hallo' ist eine Zeichenkette. Also ursprünglich ist `fragen` eine Zeichenkette, bis Du sie dann mit `encode()` als Bytes kodierst. Der reguläre Ausdruck ist eine Zeichenkette. Ein literales Bytes-Objekt hat ein kleines b vor den Anführungszeichen, also beispielsweise b'hallo' ist ein Bytes-Objekt. Wo da jetzt was hin muss, kommt darauf an was Du machen willst. Normalerweise dekodiert man Bytes so früh wie möglich in Zeichenketten, und Zeichenketten so spät wie möglich in Bytes. Am besten lässt man das auch von anderen erledigen. `Popen()`-Objekten kann man beispielsweise ein `encoding`-Argument übergeben, und dann kann man Zeichenketten schreiben und lesen.
“Pets are always a great help in times of stress. And in times of starvation too, o'course.” — Terry Pratchett, Small Gods
brainstir
User
Beiträge: 25
Registriert: Dienstag 26. September 2017, 08:36

Dienstag 11. September 2018, 20:01

Also das Problem scheint hier zu liegen:

Code: Alles auswählen

def setClipboardData(data):
    p = subprocess.Popen(['xclip','-selection','clipboard'], stdin=subprocess.PIPE)
    p.stdin.write(data)
    p.stdin.close()
    retcode = p.wait()
speziell bei

Code: Alles auswählen

    p.stdin.write(data)
bekomme Ich
a bytes-like object is required, not 'str'


Wie mache Ich jetzt aus data ein byte-like objekt?
Ich habs mit
p.stdin.write(b'data')
und
def setClipboardData(b'data'):
probiert, aber es kommt immer noch die selbe fehlermeldung...

Wo ändere Ich das?
Benutzeravatar
__blackjack__
User
Beiträge: 1226
Registriert: Samstag 2. Juni 2018, 10:21

Dienstag 11. September 2018, 20:32

@brainstir: Du bekommst ziemlich sicher bei beiden Varianten *nicht* die selbe Fehlermeldung. Im ersten Fall bekommst Du gar keine Fehlermeldung, aber es macht nicht das was Du willst, und die zweite Variante ist kein gültiges Python, da fällt schon der Compiler drüber.

Also noch mal: `Popen` kann man auch eine Kodierung übergeben, dann ist `stdin` eine Textdatei und keine Binärdatei.
“Pets are always a great help in times of stress. And in times of starvation too, o'course.” — Terry Pratchett, Small Gods
Sirius3
User
Beiträge: 8414
Registriert: Sonntag 21. Oktober 2012, 17:20

Mittwoch 12. September 2018, 22:22

Sicherer ist es, die Clipboard-Daten als Bytes zu lassen.

Code: Alles auswählen

def get_clipboard_data():
    return subprocess.check_output(['xclip','-selection', 'clipboard', '-o'])

def set_clipboard_data(data):
    p = subprocess.Popen(['xclip','-selection','clipboard'], stdin=subprocess.PIPE)
    p.communicate(data)

def einfuegen(fragen):
    try:
        clipboard_data = get_clipboard_data()
    except subprocess.CalledProcessError:
        clipboard_data = ""
    parts = re.split('(https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+)', fragen)
    for index, part in enumerate(parts):
        set_clipboard_data(part.encode())
        keyboard.send_keys("<ctrl>+v")
        if index % 2: #odd
            # send space after second string (URL)
            time.sleep(0.2)
            keyboard.send_keys(" ") 
        time.sleep(0.3)
    set_clipboard_data(clipboard_data)
Antworten