-2

I am trying this sample code that I found which is really really good. I am also trying to figure out the same thing to find an item and scroll to it, but this time I wanted to match the the string which has the EXACT WORD "cat".

Example matches:

  • cat

  • tom cat

  • dog and cat

  • super cat

To make it very simple I am just trying to match an exact word in a string. Take this sample code as an example:

import re
s= "1  tom cat"
s2 = "2 thundercat"

if re.search(r'\bcat\b',s2):
    print("There is an EXACT word cat in that string")
else:
    print("There is NO EXACT word cat in that string")

Input: s
Output: There is an EXACT word cat in that string

Input: s2
Output: There is NO EXACT word cat in that string

But this time I am using the regular expression r'\bcat\b' to check if the string has the exact word cat AND SCROLL to it

I configured it & tried this code. I just did some minor changes like the QtCore.Qt.MatchRegExp into QtCore.Qt.MatchContains which scrolls me to the word that contains "cat".

from PyQt5 import QtCore,QtWidgets

app=QtWidgets.QApplication([])

def scroll():
    #QtCore.QRegularExpression(r'\b'+'cat'+'\b')
    item = listWidget.findItems('cat', QtCore.Qt.MatchContains)[0]
    item.setSelected(True)

window = QtWidgets.QDialog()
window.setLayout(QtWidgets.QVBoxLayout())
listWidget = QtWidgets.QListWidget()
window.layout().addWidget(listWidget)


cats = ["thundercat","cat","tom cat","dogcat","dog and cat","super cat","lazycat"]

for i,cat in enumerate(cats):
    QtWidgets.QListWidgetItem(f"{i}  {cat}", listWidget)

btn = QtWidgets.QPushButton('Scroll')
btn.clicked.connect(scroll)
window.layout().addWidget(btn)
window.show()
app.exec_()

sample gui

Now I have read about this Qt::MatchRegularExpression & I was hoping to use this to achieve my goal which is scroll to the string with the EXACT WORD which contains "cat". Based on the documentation it says here.

Qt::MatchRegularExpression

Performs string-based matching using a regular expression as the search term. Uses QRegularExpression. When using this flag, a QRegularExpression object can be passed as parameter and will directly be used to perform the search. The case sensitivity flag will be ignored as the QRegularExpression object is expected to be fully configured. This enum value was added in Qt 5.15.

I can't seem to figure this out QRegularExpression object can be passed as parameter and will directly be used to perform the search I tried multiple solutions to what it meant by the object can be passed.

Things I Experimented

1.) I tried this, however it's giving me an IndexError: list index out of range error indicating that it has not found anything. I wonder why since the regex seems correct.

item = listWidget.findItems(r'\b'+'cat'+'\b',QtCore.Qt.MatchRegularExpression)[0]

2.) I tried this one still gives me this type of error.

File "finditems.py", line 7, in scroll
    item = listWidget.findItems('cat',QtCore.Qt.MatchRegularExpression(QtCore.QRegularExpression(r'\b'+'cat'+'\b')))[0]
TypeError: 'MatchFlag' object is not callable

3.) Again I tried this one but I think I got it wrong since the first parameter of the findItems function needs to be a str type.

File "finditems.py", line 7, in scroll
    item = listWidget.findItems(QtCore.QRegularExpression(r'\b'+'cat'+'\b'),QtCore.Qt.MatchRegularExpression)[0]
TypeError: findItems(self, str, Union[Qt.MatchFlags, Qt.MatchFlag]): argument 1 has unexpected type 'QRegularExpression'

How can I properly pass this QRegularExpression object as stated in the docs so that I can scroll to the string which has the EXACT WORD which is "cat"?

Ice Bear
  • 2,676
  • 1
  • 8
  • 24
  • 1
    I cannot test your code as I should, since I cannot install Qt 5.15 yet, but: 1) should use the `r` prefix in the last bit of the regex too (the same goes for point 3 too); 2) `MatchRegularExpression` is an enum *value*, and values are not callable: you can *create* the flag using `QtCore.Qt.MatchFlag(QtCore.Qt.MatchRegularExpression)` – musicamante Jan 04 '21 at 03:14
  • @IceBear Your question is unclear. I don't see any item that contains exactly "cat", the closest thing is an item with a text "1 cat", do you want to search for the item with text "foo_number cat"? – eyllanesc Jan 04 '21 at 03:22
  • @eyllanesc I think I've explained it right... you can see the code there there is a `list` variable `cats` also I have included an example matches I mentioned. What the program does is it scrolls to the **ITEM** which contains "cat" if I put the flag `QtCore.Qt.MatchContains`. Now what I wanted to do is the **EXACT WORD** that has the word "cat" like for example matches that the program would scroll are: `cat` , `tom cat` , `dog and cat`, `super cat` . Because there is an exact word "cat" itself you can also see from my regular expression on what I am trying to accomplish, thanks – Ice Bear Jan 04 '21 at 03:27
  • @IceBear The list can contain the word "cat" but the items contain the words formed with the expression `f"{i} {cat}"` and that are clearly shown in the image you provide – eyllanesc Jan 04 '21 at 03:29
  • yes yes, the string that would be displayed is like that. eg `0 thundercat`. What I just wanted to do is *scroll* to the **string** which has the **exact** word "`cat`" when I press the button. Again ex: `cat , tom cat , dog and cat, super cat` & I was thinking if how could I do it with `QRegularExpression` but I am having trouble how to pass it as stated in the docs. – Ice Bear Jan 04 '21 at 03:33
  • btw @musicamante I tried this `listWidget.findItems(r'\b'+'cat'+'\b',QtCore.Qt.MatchFlag(QtCore.Qt.MatchRegularExpression))[0]` but got an `IndexError: list index out of range` I think it does not recognize the regex. – Ice Bear Jan 04 '21 at 03:35
  • @IceBear Please, **read** what it's been suggested to you: you should use the "r" prefix in the last bit of the regex too. – musicamante Jan 04 '21 at 04:07
  • yeah thanks got it with that! @musicamante – Ice Bear Jan 04 '21 at 04:10

1 Answers1

1

According to what you indicate, you want to find the words that contain the word cat, so you must use the following:

items = listWidget.findItems(r"\bcat\b", QtCore.Qt.MatchRegularExpression)
for item in items:
    print(item.text())

Output

1  cat
2  tom cat
4  dog and cat
5  super cat

Note: r'\b'+'cat'+'\b' is not r"\bcat\b" since the second \b is not escaped, so you must change it to r'\b'+'cat'+r'\b'


On the other hand, if the objective is to search for the next item then you must store the information of the previous item as the row and use that information to select the new item.

def scroll():
    new_item = None
    last_selected_row = -1
    selected_items = listWidget.selectedItems()
    if selected_items:
        last_selected_row = listWidget.row(selected_items[0])
    items = listWidget.findItems(r"\bcat\b", QtCore.Qt.MatchRegularExpression)
    for item in items:
        if listWidget.row(item) > last_selected_row:
            new_item = item
            break
    if new_item:
        new_item.setSelected(True)
        listWidget.scrollToItem(new_item, QtWidgets.QAbstractItemView.PositionAtTop)
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • hello! thanks for the answer...let's go to the first code you provided cause it works but I tried it but it only gets the `cat` & as I mentioned on the question I was trying to scroll to the string that has the **exact** word cat. Now when I changed the cats list to like this `cats = ["thundercat","loof","tom cat","dogcat","dog and cat","super cat","lazycat"]` it's supposed to scroll to "tom cat" since there is a solo word "cat" there in that string... that is why my regex was like this initially `r"\b"+"cat"+"\b"` cause I was trying to match the exact word cat in that particular string. – Ice Bear Jan 04 '21 at 03:47
  • please take a look at my question as I've done some edits and provided an example. – Ice Bear Jan 04 '21 at 03:57
  • oh my @eyllanesc! It worked! but may I ask why didn't it work when I did this `r'\b'+'cat'+'\b'`. Hmmmm that's weird I think there's something about the regex in terms of escaping... This works `r"\bcat\b"` but this doesn't `r'\b'+'cat'+'\b'` , I think I was doing it wrong all along with the regex but I got more confused. I needed to concat cause "cat" was just an example & there are other words that I am putting there to match. – Ice Bear Jan 04 '21 at 04:01
  • 1
    @IceBear you have to escape the second "\b": `r'\b'+'cat'+r'\b'` – eyllanesc Jan 04 '21 at 04:03
  • yeah that's also what I've thought jsut right now... I've been spending almost 2 hours with this & it was just a simple escaping problem I guess....... could you please change the correct regex as it is considered to be the answer. Thanks – Ice Bear Jan 04 '21 at 04:05
  • @IceBear The `r'\b'` was already suggested in the comments to your question, and it's pretty obvious that if you concat a *raw* string with a *standard* string, the result is that the part containing the standard string is **not** using the raw format. Please, try to carefully follow what is being suggested to you. – musicamante Jan 04 '21 at 04:06
  • @IceBear What do you want me to change in my answer? It seems better to use `r"\bcat\b"` than `r'\b'+'cat'+r'\b'` since I do not see how to implement concatenation, on the other hand I have added a note about it – eyllanesc Jan 04 '21 at 04:08
  • @musicamante yeah thanks sorry for that I got really tired & did not catch that comment of yours , yeah you mentioned it here `1) should use the r prefix in the last bit of the regex too (the same goes for point 3 too)` – Ice Bear Jan 04 '21 at 04:08
  • @eyllanesc okay that's cool I've seen it, thanks – Ice Bear Jan 04 '21 at 04:08