:: Visual Foxpro, Foxpro for DOS
? VAL("56e0821106c")
Равиль
Автор

Сообщений: 6692
Откуда: Уфа
Дата регистрации: 01.08.2003
Привет !
Случайно нарвался ... хотел простейший способ извлечь первую цифровую часть строки

? VAL("123ghj0821106c")
? VAL("123567qwer0821106c")

? VAL("56e0821106c") && ошибка переполнения (вычисляет как e в степени)

*!* ps Пришлось сделать так, подменяя символы "eE" на что-то другое, например "|"

? VAL(CHRTRAN("56E082kl116706c","eE","||"))


------------------
Тяжело согнать курсором муху с монитора ...




Исправлено 1 раз(а). Последнее : Равиль, 19.12.24 07:22
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
FaustGreen

Сообщений: 145
Дата регистрации: 26.06.2023
Как по мне плохая практика, использовать инструменты для решения задач, которые для этого не предназначены.
Первые уже всплыл: строковое выражение оказалось конвертируемым в число, хотя вы этого не ожидали. А вдруг еще, где то не так отработает ...
Там простенькую функцию можно написать за пару минут, и будет работать надежно.

p.s. А что если ваше число вообще не содержит числовой части? Такие случаи возможны? Обработка таких ситуаций есть?



Исправлено 1 раз(а). Последнее : FaustGreen, 19.12.24 12:48
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
akvvohinc

Сообщений: 4560
Откуда: Москва
Дата регистрации: 11.11.2008
Ещё нужно помнить, что:

- десятичный разделитель, с которым привык работать, может не совпасть с тем, как он изображается в принимаемой строке.
Например, ты работаешь при SET POINT TO '.' (точка), а в строке разделителем является запятая.

- денежный символ в начале строки "не остановит" функцию VAL()
? VAL('$41rc') && 41

- комбинация "0x" в начале строки подразумевает, что далее может идти 16-ричное число
? VAL('0x20rt') && 32

Это первое, что пришло в голову. Возможно, есть и другие варианты - надо аккуратно пройтись по всем типам данных.
Тип данных Blob VAL(), похоже, не понимает
? VAL('0h45rt') && 0

Да даже знаки плюс или минус можно трактовать по-разному - обычный это символ или знак числа.

А символ табуляции - CHR(9), похоже, в некоторых случаях вообще может ввести VAL() в ступор.
Может, конечно, у меня Фокс "не последней модели", но сразу после его запуска я получаю такой результат:
? VAL(CHR(9)+'$1') && 1
? VAL(CHR(9)+'$10') && 10
? VAL(CHR(9)+'$1') && 10 ?
? VAL(CHR(9)+' $1') && 1
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
sphinx

Сообщений: 31892
Откуда: Каменск-Уральски
Дата регистрации: 22.11.2006
Цитата:
хотел простейший способ извлечь первую цифровую часть строки

Всю задачу руки (в скорости ответов с Сергеем сложно соперничать) не дойдут посмотреть, но как-то давно еще Максимов писал типа CHR(<символы/буквы> , ''). Но тебе, Равиль, как я понял, нужны только первые цифры, за буквами надо обрезать. Без циклов точно это можно, пока сам не пощупаю за вымя - навскидку не предложу вариант.


------------------
"Veni, vidi, vici!"(с)
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
sphinx

Сообщений: 31892
Откуда: Каменск-Уральски
Дата регистрации: 22.11.2006
VAL() - да, это тоже первое, что пришло в голову. Но надо смотреть разные варианты, нет полной уверенности, что это всегда годно обрежет.

Цитата:
Возможно, есть и другие варианты - надо аккуратно пройтись по всем типам данных.
Вот и я про это. Исследователей хватает, сообща точно решим задачу.
Я с ДР пока выпаду на время, потом подключусь, я за любой кипеж, кроме голодовки.


------------------
"Veni, vidi, vici!"(с)




Исправлено 1 раз(а). Последнее : sphinx, 20.12.24 00:18
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
akvvohinc

Сообщений: 4560
Откуда: Москва
Дата регистрации: 11.11.2008
sphinx
нет полной уверенности, что это всегда годно обрежет.
Всегда годно обрезать можно лишь зная, что есть "число" (может быть числом) в принимаемой строке.

Как простой пример сказанного:
"12,5aaaaaaa" - это 12 или 12.5
"+12" - это 12 или 0

В общем, я бы потребовал "ТЗ на число" ещё до начала работы.
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
Равиль
Автор

Сообщений: 6692
Откуда: Уфа
Дата регистрации: 01.08.2003
Спасибо всем за основательный подход к вопросу ! а как же иначе !

Извините, я должен был оговориться, что задача не столь строга на самом деле

Принимаемая строка - это строка поиска, набираемая пользователями и мне полезно выделить первую цифровую часть в дополнительный параметр, чтобы сузить/расширить круг поиска.

Благодарен за подсказки, буду учитывать поведение VAL() - также подменяя символы "hHxX" на тот же разделитель "||||" чтобы избежать "переполнения".

ps и точки с запятыми и прочие символы уже убирались


------------------
Тяжело согнать курсором муху с монитора ...




Исправлено 1 раз(а). Последнее : Равиль, 20.12.24 06:55
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
Владимир Максимов

Сообщений: 14146
Откуда: Москва
Дата регистрации: 02.09.2000
Простейший способ оставить только цифры - это сначала заменить цифры, а затем полученную строку использовать как маску исключения. Исключение на исключение

* Исходная переменная
var1 = "56e0821106c"
* Маска исключения всех символов, кроме цифр
maskDigit = "0123456789"
maskNotDigit = ChrTran(var1, maskDigit, space(len(masktDigit)))
* Собственно исключение символов, отличных от цифр
?CharTran(var1, maskNotDigit, space(len(maskNotDigit)))

space() нужен для того, чтобы вместо замещаемых цифр оставались пробелы. Иначе цифры из разных мест строки "склеются" вместе



Исправлено 1 раз(а). Последнее : Владимир Максимов, 22.12.24 13:55
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
Равиль
Автор

Сообщений: 6692
Откуда: Уфа
Дата регистрации: 01.08.2003
Владимир Максимов
Простейший способ оставить только цифры - это сначала заменить цифры, а затем полученную строку использовать как маску исключения. Исключение на исключение

Владимир :hi:


------------------
Тяжело согнать курсором муху с монитора ...
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
akvvohinc

Сообщений: 4560
Откуда: Москва
Дата регистрации: 11.11.2008
Владимир Максимов
Простейший способ оставить только цифры - это сначала заменить цифры, а затем полученную строку использовать как маску исключения.
Не согласен.

Проще использовать одну функцию SYS(15), чем две CHRTRAN():
1) такой алгоритм гораздо понятнее - ведь сразу делается именно то, что требуется.
2) да и работать будет в 20-30 раз быстрее (и чем длиннее строка, тем большим будет выигрыш в скорости)
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
chunihin-df

Сообщений: 88
Откуда: Тюмень
Дата регистрации: 18.11.2013
akvvohinc
Проще использовать одну функцию SYS(15), чем две CHRTRAN():
Вот так?

SYS(15, STUFF(SPACE(255), ASC('0'), 10, '0123456789'), "test123as45d67d8e910")

STREXTRACT(LTRIM(SYS(15, STUFF(SPACE(255), ASC('0'), 10, '0123456789'), "test12ф3as4я5d6у7d8e910")), "", " ")



Исправлено 2 раз(а). Последнее : chunihin-df, 23.12.24 17:32
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
akvvohinc

Сообщений: 4560
Откуда: Москва
Дата регистрации: 11.11.2008
Да.

Но если речь не об однократном использовании, то таблицу лучше сохранить.
tabl = PADR(SPACE(47)+[0123456789], 255)

А во второй строке нельзя теперь просто использовать VAL() ?

А если число нужно как строка, то я бы всё равно использовал GETWORDNUM() - не нужен LTRIM(), меньше параметров, да и вообще - "вернуть первое слово" - именно то, что нам нужно
GETWORDNUM(SYS(15, tabl, "test12ф3as4я5d6у7d8e910"), 1)



Исправлено 1 раз(а). Последнее : akvvohinc, 23.12.24 18:30
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
ABB

Сообщений: 165
Откуда: Санкт-Петербург
Дата регистрации: 21.10.2006
Я предпочел бы следующую функцию

*Пример вызова: в примере вызова функции передается строка "56e0821106c" и начальный индекс 1.
lcString = "56Ё082kl116706c"
? GetFirstDigits(lcString, 1)
FUNCTION GetFirstDigits
PARAMETERS tcString, tnIndex
* Функция GetFirstDigits: принимает два параметра — строку tcString и индекс текущего символа tnIndex.
LOCAL lcChar, llIsDigit
*Проверка корректности входных данных: если строка пустая или её тип не строковый, возвращается пустая строка.
IF EMPTY(tcString) OR VARTYPE(tcString) <> "C"
RETURN ""
ENDIF
*Проверка окончания строки: если индекс выходит за пределы длины строки, возвращается пустая строка.
IF tnIndex > LEN(tcString)
RETURN ""
ENDIF
*Извлечение символа: функция берет текущий символ строки через SUBSTR(tcString, tnIndex, 1) и сохраняет его в переменную lcChar.
lcChar = SUBSTR(tcString, tnIndex, 1)
* Проверка на цифру: используется проверка, чтобы определить, является ли символ цифрой.
llIsDigit = INLIST(lcChar, "0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
* Рекурсивный вызов: если символ является цифрой, он добавляется к результату и вызывается следующая итерация функции с увеличенным индексом.
* Если символ не цифра, возвращается пустая строка.
IF llIsDigit
RETURN lcChar + GetFirstDigits(tcString, tnIndex + 1)
ELSE
RETURN ""
ENDIF
ENDFUNC
Ratings: 0 negative/1 positive
Re: ? VAL("56e0821106c")
chunihin-df

Сообщений: 88
Откуда: Тюмень
Дата регистрации: 18.11.2013
akvvohinc
tabl = PADR(SPACE(47)+[0123456789], 255)

А во второй строке нельзя теперь просто использовать VAL() ?

А если число нужно как строка, то я бы всё равно использовал GETWORDNUM() - не нужен LTRIM(), меньше параметров, да и вообще - "вернуть первое слово" - именно то, что нам нужно
GETWORDNUM(SYS(15, tabl, "test12ф3as4я5d6у7d8e910"), 1)

Вот так наверное, смысл переменную определять?
#define tabl 0h2020

GETWORDNUM(SYS(15, tabl, "test12ф3as4я5d6у7d8e910"), 1)



Исправлено 1 раз(а). Последнее : Joys, 25.12.24 03:36
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
ABB

Сообщений: 165
Откуда: Санкт-Петербург
Дата регистрации: 21.10.2006
Когда я вижу такой код, то вспоминую принцип KISS.
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
chunihin-df

Сообщений: 88
Откуда: Тюмень
Дата регистрации: 18.11.2013
Ну, к KISS это не имеет отношения.
Это к вопросу о том зачем выносить таблицу соответствия в переменную
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
akvvohinc

Сообщений: 4560
Откуда: Москва
Дата регистрации: 11.11.2008
chunihin-df
Это к вопросу о том зачем выносить таблицу соответствия в переменную
Причина может быть такой:
Такая константа немалой длины будет попадать в fxp каждый раз, когда используется.
То есть fxp может прилично распухнуть "из ничего".
В то же время выигрыш в скорости по сравнению с обращением к переменной будет минимальным.

И это не говоря уж о том, что такую константу просто трудно набрать без ошибки.
Скажем, у меня ваш код выдал результат "со сдвигом на 1 байт":
01

В общем, на мой взгляд, должна быть очень веская причина, чтобы использовать такую константу.
Например, когда задача предусматривает выполнение циклов в сотни миллионов повторений.

Цикл на 100 миллионов повторений с константой у меня отработал лишь на 3 секунды быстрее, чем с переменной (3 сек. на 100'000'000 итераций!).
Пока мне даже близко не встречались такие "серьёзные" задачи.

(вариант с двумя CHRT(), предложенный Владимиром, проиграл "константе" 73 секунды. И это на такой, довольно короткой, строке!)



Исправлено 3 раз(а). Последнее : akvvohinc, 24.12.24 01:23
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
akvvohinc

Сообщений: 4560
Откуда: Москва
Дата регистрации: 11.11.2008
ABB
Я предпочел бы следующую функцию
Предпочли бы, но почему-то постеснялись хоть как-то это аргументировать.

А я бы вообще запретил использовать рекурсию без крайней необходимости - никогда не знаешь, где, когда и у кого "рванёт".
Вам придется заранее предполагать глубину возможной рекурсии и заставлять юзеров проверять/изменять свои конфиги
на предмет соответствующих значений таких параметров как MVCOUNT и/или STACKSIZE, которые редко кому приходится трогать.

Понятно, что для какой-то "узкой" задачи - скажем, разово извлечь десяток символов из строки, скорость неважна,
но в общем случае посимвольная обработка - та ещё черепаха.

Так какие же плюсы вы видите у предложенного варианта?
(посимвольная обработка, "отягощённая" рекурсией)



Исправлено 1 раз(а). Последнее : akvvohinc, 24.12.24 02:53
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
chunihin-df

Сообщений: 88
Откуда: Тюмень
Дата регистрации: 18.11.2013
Подозреваю, что GETWORDNUM(SYS(15, PADR(SPACE(47)+[0123456789], 255), m.lcStr), 1) отработает за такое же время, что и GETWORDNUM(SYS(15, tabl, m.lcStr), 1)

Хотя, если изначально требуется получить на выходе числовой тип, то быстрее val ничего не придумать.
IF NOT BETWEEN(ASC(LEFT(LTRIM(lcStr),1)), 48, 57)
RETURN 0
ENDIF
IF BETWEEN(ASC(SUBST(LTRIM(lcStr,1," ", "0"),16,1)), 48, 57)
RETURN 0
ENDIF
RETURN VAL(CHRTRAN(LEFT(LTRIM(lcStr,1," ", "0"),15), 'Ee'+SET("Point"), 'aaa'))



P.S. не знаю стоит ли переживать из-за распухания fxp, а вот из-за распухания форума стоит, надо как-то удалить этот длинный литерал 0h2020... , я уже не смогу отредактировать сообщение.



Исправлено 5 раз(а). Последнее : chunihin-df, 24.12.24 08:49
Ratings: 0 negative/0 positive
Re: ? VAL("56e0821106c")
ABB

Сообщений: 165
Откуда: Санкт-Петербург
Дата регистрации: 21.10.2006
akvvohinc
какие же плюсы вы видите у предложенного варианта?
(посимвольная обработка, "отягощённая" рекурсией)
Первая и главная - понимание кода.
Разбираться в матрешке функций еще то занятие. Кодер и сам не вспомнит через некоторое время, что он там делал.
Второе - модификация кода. Предположим, что надо выбирать числа только в том случае если за числом идет ~
Не нравиться рекурсия - к вашим услугам простой цикл.
Лозунг ""Экономь миллисекунду" не всегда хорош.



Исправлено 1 раз(а). Последнее : ABB, 24.12.24 09:58
Ratings: 0 negative/0 positive


Извините, только зарегистрированные пользователи могут оставлять сообщения в этом форуме.

On-line: 22 (Гостей: 22)

© 2000-2025 Fox Club 
Яндекс.Метрика