Calc:Makro für String in Wert-Konvertierung

Hi, Hallo, Aloha
Ich habe mir ein Skript zusammengebastelt, das Text-Zellen mit Zahlen ('12389) in Werte umwandelt, analog der “Einfügen als Wert”-Funktion.
Zwei Probleme:

  1. Leider funktioniert die If…Then-Else-Funktion nicht, die verhindern soll, daß bei reinem
    Text eine 0 (NUll) in die Zelle geschrieben wird.
  2. Ich hätte das Skript gern für mehrere markierte Zellen (.Range) erweitert

Hier meine Makrozeilen:

Sub InWertWandeln
  ' isNumeric() prüft lediglich, ob der übergebene Ausdruck in eine gleichlautende Zahl,
  ' umgewandelt werden kann, also ob es sich um Ziffern handelt.
     oDoc = thisComponent
    mysheet = oDoc.CurrentController.ActiveSheet
    oActiveCell=oDoc.currentSelection
    oString=oActiveCell.string
     Msgbox oString  REM Zur Kontrolle
    Wert=Val(oString)
    If IsNumeric(Wert) then
     Msgbox Wert
    oActivecell.setValue(Wert)
      else
    Msgbox "Ist keine Zahl"
     exit Sub
   end if
  end sub`

Du machst mit Val(oString) Wert zu einem numerischen Wert, also liefert IsNumeric(Wert) immer TRUE (Die If ... then ... else kannst Du dir also eigentlich sparen). Du müsstest Dir irgendwie merken was der String vorher war, dann mit dem durch Val konvertierten Wert vergleichen und ein Entscheidungkriterium finden, ob sich da was geändert hat. Noch schlimmer wird es mit einer Erweiterung auf Ranges, denn den Range müsstest Du parsen und dann Loops über Spalten und Zeilen bauen. Insgesamt sehe ich für diesen Ansatz einen unverhältnismäßig hohen Aufwand, der mit Find & Replace in wenigen Augenblicken manuell erledigt ist (dafür kann man sogar den Makro-Recorder benutzen und ein Makro aufzeichnen). Siehe dazu meine Antwort.

PS: Natürlich mag es auch Gründe geben, das alles mal selber zu programmieren.

Da möchte ich gerne noch verstehen, warum es für diese Aufgabe eine 'Makro" braucht.
Sowohl >Data>Text to columns... (für einzelne Spalten) als auch
Find & Replace(mit Regex .* in Search und $0 oder & in Replace) sollten das tun - wie ja auch der aufgezeichnete Makro von @anon73440385 zeigt.
Falls es wirklich eine Sub sein muss, die man von anderen Sub aus aufrufen kann, bleibt die Frage, ob es sinnvoll ist, sie auf die CurrentSelection anzuwenden.
Naja. Für den Fall der Fälle poste ich auch noch Code. Dazu nehme ich jetzt das Antwort-Tool.

@Lupp - ich brauche das nicht, aber die Frage war danach und soweit ich den OP verstanden habe, geht es nur darum, einen Range zu markieren und mit der rechten Maustaste über ein Kontextmenü die Konvertierung zu vereinfachen. Alles andere ist mir eigentlich relativ egal. Ich würde mir da nur zu Übungszwecken eine Aufgabe draus machen, falls ich mal wirklich in die Makroprgrammierung einsteigen wollte (ist mir aber zu undurchsichtig bzw. ich bin zu doof dazu).

Hallo,

in Anlehnung an den Kommentar hier eine Lösung basierend auf Bearbeiten -> Suchen und Ersetzen:

Suchen-Feld: .*
Ersetzen:Feld: $0
Option 1 Nur in Auswahl
Option 2 Reguläre Ausdrücke

Damit erspart man sich die Neuerfindung des Rades und benutzt die in LibreOffice bereits enthaltene Logik zur Konvertierung von Text nach Zahlen.

Das folgende mit dem Makrorecorder aufgenommene Makro kann die oben ausgeführten manuellen Schritte mit einem Makroaufruf erledigen (zumindest in meinem Test unter LibreOffice 6.2.5.2 tut es das)

sub ConvertToNumber

dim document   as object
dim dispatcher as object

document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")

dim args1(20) as new com.sun.star.beans.PropertyValue
args1(0).Name = "SearchItem.StyleFamily"
args1(0).Value = 2
args1(1).Name = "SearchItem.CellType"
args1(1).Value = 0
args1(2).Name = "SearchItem.RowDirection"
args1(2).Value = true
args1(3).Name = "SearchItem.AllTables"
args1(3).Value = false
args1(4).Name = "SearchItem.SearchFiltered"
args1(4).Value = false
args1(5).Name = "SearchItem.Backward"
args1(5).Value = false
args1(6).Name = "SearchItem.Pattern"
args1(6).Value = false
args1(7).Name = "SearchItem.Content"
args1(7).Value = false
args1(8).Name = "SearchItem.AsianOptions"
args1(8).Value = false
args1(9).Name = "SearchItem.AlgorithmType"
args1(9).Value = 1
args1(10).Name = "SearchItem.SearchFlags"
args1(10).Value = 71680
args1(11).Name = "SearchItem.SearchString"
args1(11).Value = ".*"
args1(12).Name = "SearchItem.ReplaceString"
args1(12).Value = "$0"
args1(13).Name = "SearchItem.Locale"
args1(13).Value = 255
args1(14).Name = "SearchItem.ChangedChars"
args1(14).Value = 2
args1(15).Name = "SearchItem.DeletedChars"
args1(15).Value = 2
args1(16).Name = "SearchItem.InsertedChars"
args1(16).Value = 2
args1(17).Name = "SearchItem.TransliterateFlags"
args1(17).Value = 1073742080
args1(18).Name = "SearchItem.Command"
args1(18).Value = 3
args1(19).Name = "SearchItem.SearchFormatted"
args1(19).Value = false
args1(20).Name = "SearchItem.AlgorithmType2"
args1(20).Value = 2

dispatcher.executeDispatch(document, ".uno:ExecuteSearch", "", 0, args1())

dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "Visible"
args2(0).Value = false

dispatcher.executeDispatch(document, ".uno:SearchResultsDialog", "", 0, args2())

end sub

Hinweis zur Verwendung: Range markieren und dann Makro aufrufen.

Hallo Opaque,

für Deinen “Mitschnitt” danke ich Dir ganz herzlich. Das Makro macht ganz genau das, was es soll. Jetzt kann ich das Makro in das Kontextmenü (re. Maustaste) aufnehmen und loslegen.

Freundliche Grüße aus der Mitte Deutschlands

Dann wäre es nett, wenn Du diese Antwort durch Klicken auf das (:heavy_check_mark:) oben am Anfang der Antwort auf beantwortet (wird grün dabei) setzen würdest.

Da ist aber kein Haken für [beantwortet] oder [geschlossen] - nur der für [korrekte Antwort]. Was ich auch gemacht habe…

Perfekt - genau den habe ich gemeint.
Noch ein Hinweis - was ich grade bemerkt habe: Wenn man nur eine einzige Zelle umwandeln will, muss man bei gedrückter Maustatste kurz eine Nachbarzelle ansteuern und dann zurück auf die zu konvertierende Zelle, so daß diese grau hinterlegt ist. Erst dann kann man das Makro aufrufen.

Gut zu wissen. Das ist wie das Verschieben einer einzigen Zelle mit der Maus. Erst wenn die Zelle hellblau ist lässt sich dies vollziehen. Das nennt man wohl Fokus.
Danke

Code:

Sub walkSelectionMakeNumbersIfPossible(pEvent)
sel = ThisComponent.CurrentSelection
If sel.SupportsService("com.sun.star.sheet.SheetCellRanges") Then
 For Each rg In sel
  makeNumbers(rg)
 Next rg
 Exit Sub
End If
If sel.SupportsService("com.sun.star.sheet.SheetCellRange") Then
 makeNumbers(sel)
 Exit Sub
End If
End Sub

Sub makeNumbers(pRange)
fa = createUnoService("com.sun.star.sheet.FunctionAccess")
da = pRange.getDataArray
u1 = Ubound(da) : u2 = Ubound(da(0))
For j = 0 To u1
 For k = 0 To u2
  jkS = da(j)(k)
  If TypeName(jkS)="String" Then
   h = tryValue(jkS, fa)
   If NOT IsNull(h) Then
    da(j)(k) = h
   End If
  End If
 Next k
Next j
pRange.setDataArray(da)
End Sub

Function tryValue(pString, pFA)
tryValue = Null
On Local Error Goto errorExit
tryValue = pFA.callFunction("VALUE", Array(pString))
errorExit:
End Function 

Es gibt zwar auch die BASIC-Funktionen IsNumeric() (buggy; akzeptiert z.B. kein führendes +) und Val().
Ich habe hier 'mal die Calc-Funktion VALUE() genommen. Da gibt es natürlich auch Zweifelsfragen. Man kann aber dem FunctionAccess-Objekt z.B. eine Locale nach Wunsch verpassen.
(CurrentSelection liefert übrigens auch eine einzelne Zelle, die nur den Fokus hat, aber nicht im vollen Sinn selektiert ist. Eigentlich halte ich das ja für einen Fehler …)

Hallo Lupp,
danke für das Makro. Es funzt vorzüglich und hat auch mindestens drei Vorteile:

  1. Formatierung der Zelle(n) wird beibehalten
  2. Prozedur ist auch auf eine einzelne Zelle anwendbar
  3. Auch Formeln und Datums werden in Werte gewandelt.

Bravo, gute Arbeit !