Могу ли я выбрать количество символов в функции format_string

#scala #apache-spark #apache-spark-sql

Вопрос:

У меня есть фрейм данных со столбцом StringType ssn , который называется следующим содержимым:

  ---------  | ssn|  ---------  |986-69-2371| |957305210| |965741549| |996118261| |946899347| |974393395| |998771903| |949429820| |983662042| |923785843| |948-84-1328| |971-48-1142| |972-79-2371| |989498321| |943129824| |976849729| |949-79-5213| |924761199| |991718011| |988-25-4619|  ---------   

Как вы можете видеть, содержимое неоднородно. Мое намерение состоит в том, чтобы отформатировать содержимое так, чтобы все строки имели одинаковый формат (формат, который я хочу xxx-xx-xxxx ). Все строки имеют 9 номеров. Я сделал это со следующей функцией:

 df.withColumn("ssnFormat", when(col("ssn").contains("-"), col("ssn")).otherwise(format_string("%s-%s-%s", col("ssn").substr(1, 3), col("ssn").substr(4, 2), col("ssn").substr(6, 4))))  

Мне было интересно, могу ли я сделать это таким образом, чтобы в выражении формата я указывал символы, которые я хочу взять из строки?

Вот что я имею в виду:

 format_string("<-,-L", col("ssn"))  

В предыдущей инструкции я намеревался выбрать первые символы строки, затем написать дефис, 2 следующих символа, дефис, а затем остальные символы.

Я хочу выяснить, возможен ли такой способ, потому что мне не очень нравится тот факт, что я должен выполнять подстроку тех частей, которые я хочу.

Ответ №1:

Вместо этого вы можете использовать regexp_replace функцию, захватив группы xxx-xx-xxxx и заменив их $1-$2-$3 :

 val df1 = df.withColumn(  "ssn",  regexp_replace(col("ssn"), "^(\d{3})-?(\d{2})-?(\d{4})$", "$1-$2-$3") )  df1.show // -----------  //| ssn| // -----------  //|986-69-2371| //|957-30-5210| //|965-74-1549| //|996-11-8261| //|946-89-9347| //|974-39-3395| //|998-77-1903| //|949-42-9820| //|983-66-2042| //|923-78-5843| //|948-84-1328| //|971-48-1142| //|972-79-2371| //|989-49-8321| //|943-12-9824| //|976-84-9729| //|949-79-5213| //|924-76-1199| //|991-71-8011| //|988-25-4619| // -----------   

Ответ №2:

Я думаю, я знаю, что вы имеете в виду, аналогично пользовательским форматам Excel. Один из способов состоит overlay в том, чтобы вставить тире в нужную точку. Это похоже на функцию SQL STUFF . Мне все еще приходится использовать regexp_replace , чтобы убедиться, что строки находятся в согласованном формате до изменения, так что это не так элегантно:

 df.select($"ssn",   overlay(  overlay(  regexp_replace($"ssn", "-", ""), lit("-"), lit(4), lit(0)), lit("-"), lit(7), lit(0)).  alias("formatted_ssn")).show  

Мои результаты (из записной книжки Synapse, язык Scala):

Результаты записной книжки Synapse

Я думаю, что пример @blackbishop более элегантен и получил одобрение от меня. Я просто хотел записать рабочий пример overlay и сказать: «Я знаю, что вы имеете в виду, и вот как это может выглядеть в Scala, и есть более простые способы сделать это». Я также смотрел patch , но не мог заставить его работать с фреймом данных.